blob: 7520a289540b0ab6b7032516f3f4b87874f4b4cc [file] [log] [blame]
Jean-Paul Calderone8671c852011-03-02 19:26:20 -05001# Copyright (C) Jean-Paul Calderone
2# Copyright (C) Twisted Matrix Laboratories.
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -04003# See LICENSE for details.
4
5"""
6Helpers for the OpenSSL test suite, largely copied from
7U{Twisted<http://twistedmatrix.com/>}.
8"""
9
10import shutil
Rick Dean47262da2009-07-08 16:17:17 -050011import sys
Hynek Schlawack4813c0e2015-04-16 13:38:01 -040012import traceback
13
14from tempfile import mktemp, mkdtemp
15from unittest import TestCase
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -040016
Alex Gaynord0e83ad2015-09-05 13:19:43 -040017import pytest
18
Jean-Paul Calderone6462b072015-03-29 07:03:11 -040019from six import PY3
20
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050021from OpenSSL._util import exception_from_error_queue
22from OpenSSL.crypto import Error
Jean-Paul Calderone88f38b22009-07-16 16:25:19 -040023
Hynek Schlawack4813c0e2015-04-16 13:38:01 -040024
Hynek Schlawackf0e66852015-10-16 20:18:38 +020025from . import memdbg
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -080026
Alex Gaynore7f51982016-09-11 11:48:14 -040027from OpenSSL._util import ffi, lib
Jean-Paul Calderone9e4eeae2010-08-22 21:32:52 -040028
Jean-Paul Calderone210c0f32015-04-12 09:20:31 -040029
30# This is the UTF-8 encoding of the SNOWMAN unicode code point.
Alex Gaynore7f51982016-09-11 11:48:14 -040031NON_ASCII = b"\xe2\x98\x83".decode("utf-8")
Jean-Paul Calderone210c0f32015-04-12 09:20:31 -040032
33
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -040034class TestCase(TestCase):
35 """
Hynek Schlawack4813c0e2015-04-16 13:38:01 -040036 :py:class:`TestCase` adds useful testing functionality beyond what is
37 available from the standard library :py:class:`unittest.TestCase`.
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -040038 """
Alex Gaynorc88f6282015-09-05 15:32:39 -040039
Jean-Paul Calderone855331d2013-03-03 10:21:43 -080040 def run(self, result):
Jean-Paul Calderone68703ed2013-03-04 12:23:44 -080041 run = super(TestCase, self).run
42 if memdbg.heap is None:
43 return run(result)
44
Jean-Paul Calderone855331d2013-03-03 10:21:43 -080045 # Run the test as usual
46 before = set(memdbg.heap)
Jean-Paul Calderone68703ed2013-03-04 12:23:44 -080047 run(result)
Jean-Paul Calderone855331d2013-03-03 10:21:43 -080048
49 # Clean up some long-lived allocations so they won't be reported as
50 # memory leaks.
Jean-Paul Calderone9227c472013-12-31 13:47:36 -050051 lib.CRYPTO_cleanup_all_ex_data()
Paul Kehrer8ff9e3d2016-03-17 19:55:11 -040052 lib.ERR_clear_error()
Jean-Paul Calderone855331d2013-03-03 10:21:43 -080053 after = set(memdbg.heap)
54
55 if not after - before:
56 # No leaks, fast succeed
57 return
58
59 if result.wasSuccessful():
60 # If it passed, run it again with memory debugging
61 before = set(memdbg.heap)
Jean-Paul Calderone68703ed2013-03-04 12:23:44 -080062 run(result)
Jean-Paul Calderone855331d2013-03-03 10:21:43 -080063
64 # Clean up some long-lived allocations so they won't be reported as
65 # memory leaks.
Jean-Paul Calderone3f93d212014-01-01 12:36:53 -050066 lib.CRYPTO_cleanup_all_ex_data()
Paul Kehrer8ff9e3d2016-03-17 19:55:11 -040067 lib.ERR_clear_error()
Jean-Paul Calderone855331d2013-03-03 10:21:43 -080068
69 after = set(memdbg.heap)
70
71 self._reportLeaks(after - before, result)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -080072
Jean-Paul Calderone855331d2013-03-03 10:21:43 -080073 def _reportLeaks(self, leaks, result):
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -080074 def format_leak(p):
Alex Gaynorcb1db1c2015-09-06 09:07:46 -040075 """
76 c_stack looks something like this (interesting parts indicated
77 with inserted arrows not part of the data):
78
79 cpython/2.7/python(PyCFunction_Call+0x8b) [0x56265a]
80 cpython/2.7/python() [0x4d5f52]
81 cpython/2.7/python(PyEval_EvalFrameEx+0x753b) [0x4d0e1e]
82 cpython/2.7/python() [0x4d6419]
83 cpython/2.7/python() [0x4d6129]
84 cpython/2.7/python(PyEval_EvalFrameEx+0x753b) [0x4d0e1e]
85 cpython/2.7/python(PyEval_EvalCodeEx+0x1043) [0x4d3726]
86 cpython/2.7/python() [0x55fd51]
87 cpython/2.7/python(PyObject_Call+0x7e) [0x420ee6]
88 cpython/2.7/python(PyEval_CallObjectWithKeywords+0x158) [0x4d56ec]
89 _cffi_backend.so(+0xe96e) [0x7fe2e38be96e]
90 libffi.so.6(ffi_closure_unix64_inner+0x1b9) [0x7fe2e36ad819]
91 libffi.so.6(ffi_closure_unix64+0x46) [0x7fe2e36adb7c]
92
93 |----- end interesting
94 v
95 libcrypto.so.1.0.0(CRYPTO_malloc+0x64) [0x7fe2e1cef784]
96 libcrypto.so.1.0.0(lh_insert+0x16b) [0x7fe2e1d6a24b]
97 libcrypto.so.1.0.0(+0x61c18) [0x7fe2e1cf0c18]
98 libcrypto.so.1.0.0(+0x625ec) [0x7fe2e1cf15ec]
99 libcrypto.so.1.0.0(DSA_new_method+0xe6) [0x7fe2e1d524d6]
100 libcrypto.so.1.0.0(DSA_generate_parameters+0x3a) [0x7fe2e1d5364a]
101 ^
102 |----- begin interesting
103
104 _cffi__x305d4698xb539baaa.so(+0x1f397) [0x7fe2df84d397]
105 cpython/2.7/python(PyCFunction_Call+0x8b) [0x56265a]
106 cpython/2.7/python() [0x4d5f52]
107 cpython/2.7/python(PyEval_EvalFrameEx+0x753b) [0x4d0e1e]
108 cpython/2.7/python() [0x4d6419]
109 ...
110
111 Notice the stack is upside down compared to a Python traceback.
112 Identify the start and end of interesting bits and stuff it into
113 the stack we report.
114 """
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -0800115 stacks = memdbg.heap[p]
116 # Eventually look at multiple stacks for the realloc() case. For
117 # now just look at the original allocation location.
Jean-Paul Calderonec2e8b412013-03-02 16:27:55 -0800118 (size, python_stack, c_stack) = stacks[0]
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800119
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -0800120 stack = traceback.format_list(python_stack)[:-1]
Jean-Paul Calderonec2e8b412013-03-02 16:27:55 -0800121 saved = list(c_stack)
122
Alex Gaynor75690d92015-09-05 10:14:52 -0400123 # Figure the first interesting frame will be after a the
124 # cffi-compiled module
Jean-Paul Calderonec2e8b412013-03-02 16:27:55 -0800125 while c_stack and '/__pycache__/_cffi__' not in c_stack[-1]:
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -0800126 c_stack.pop()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800127
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -0800128 # Figure the last interesting frame will always be CRYPTO_malloc,
129 # since that's where we hooked in to things.
Alex Gaynorcb1db1c2015-09-06 09:07:46 -0400130 while (
131 c_stack and 'CRYPTO_malloc' not in c_stack[0] and
132 'CRYPTO_realloc' not in c_stack[0]
133 ):
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -0800134 c_stack.pop(0)
135
Jean-Paul Calderonec2e8b412013-03-02 16:27:55 -0800136 if c_stack:
137 c_stack.reverse()
138 else:
139 c_stack = saved[::-1]
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -0800140 stack.extend([frame + "\n" for frame in c_stack])
141
Jean-Paul Calderone2beac532013-03-03 17:30:36 -0800142 stack.insert(0, "Leaked (%s) at:\n")
Jean-Paul Calderone68a6f8f2013-03-01 17:56:22 -0800143 return "".join(stack)
144
Jean-Paul Calderone855331d2013-03-03 10:21:43 -0800145 if leaks:
Jean-Paul Calderone2beac532013-03-03 17:30:36 -0800146 unique_leaks = {}
Jean-Paul Calderone855331d2013-03-03 10:21:43 -0800147 for p in leaks:
Jean-Paul Calderone2beac532013-03-03 17:30:36 -0800148 size = memdbg.heap[p][-1][0]
149 new_leak = format_leak(p)
150 if new_leak not in unique_leaks:
151 unique_leaks[new_leak] = [(size, p)]
152 else:
153 unique_leaks[new_leak].append((size, p))
154 memdbg.free(p)
155
156 for (stack, allocs) in unique_leaks.iteritems():
157 allocs_accum = []
158 for (size, pointer) in allocs:
159
Jean-Paul Calderone9227c472013-12-31 13:47:36 -0500160 addr = int(ffi.cast('uintptr_t', pointer))
Jean-Paul Calderone2beac532013-03-03 17:30:36 -0800161 allocs_accum.append("%d@0x%x" % (size, addr))
162 allocs_report = ", ".join(sorted(allocs_accum))
163
Jean-Paul Calderone855331d2013-03-03 10:21:43 -0800164 result.addError(
165 self,
Jean-Paul Calderone2beac532013-03-03 17:30:36 -0800166 (None, Exception(stack % (allocs_report,)), None))
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800167
Hynek Schlawack4813c0e2015-04-16 13:38:01 -0400168 _tmpdir = None
169
Hynek Schlawack4813c0e2015-04-16 13:38:01 -0400170 @property
171 def tmpdir(self):
172 """
173 On demand create a temporary directory.
174 """
175 if self._tmpdir is not None:
176 return self._tmpdir
177
178 self._tmpdir = mkdtemp(dir=".")
179 return self._tmpdir
180
Jean-Paul Calderone855331d2013-03-03 10:21:43 -0800181 def tearDown(self):
182 """
Hynek Schlawack4813c0e2015-04-16 13:38:01 -0400183 Clean up any files or directories created using
184 :py:meth:`TestCase.mktemp`. Subclasses must invoke this method if they
185 override it or the cleanup will not occur.
Jean-Paul Calderone855331d2013-03-03 10:21:43 -0800186 """
Hynek Schlawack4813c0e2015-04-16 13:38:01 -0400187 if self._tmpdir is not None:
188 shutil.rmtree(self._tmpdir)
189
Jean-Paul Calderone1206daf2009-07-16 16:07:42 -0400190 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500191 exception_from_error_queue(Error)
Jean-Paul Calderone24b64592010-08-12 10:43:09 -0400192 except Error:
193 e = sys.exc_info()[1]
Jean-Paul Calderone1206daf2009-07-16 16:07:42 -0400194 if e.args != ([],):
Hynek Schlawack4813c0e2015-04-16 13:38:01 -0400195 self.fail(
196 "Left over errors in OpenSSL error queue: " + repr(e)
197 )
Jean-Paul Calderone1206daf2009-07-16 16:07:42 -0400198
Jean-Paul Calderone8fb53182013-12-30 08:35:49 -0500199 def assertIsInstance(self, instance, classOrTuple, message=None):
200 """
201 Fail if C{instance} is not an instance of the given class or of
202 one of the given classes.
203
204 @param instance: the object to test the type (first argument of the
205 C{isinstance} call).
206 @type instance: any.
207 @param classOrTuple: the class or classes to test against (second
208 argument of the C{isinstance} call).
209 @type classOrTuple: class, type, or tuple.
210
211 @param message: Custom text to include in the exception text if the
212 assertion fails.
213 """
Alex Gaynord0e83ad2015-09-05 13:19:43 -0400214 assert isinstance(instance, classOrTuple)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800215
Jean-Paul Calderone060a57e2011-05-04 18:02:49 -0400216 def failUnlessIn(self, containee, container, msg=None):
217 """
Alex Gaynorc88f6282015-09-05 15:32:39 -0400218 Fail the test if :py:data:`containee` is not found in
219 :py:data:`container`.
Jean-Paul Calderone060a57e2011-05-04 18:02:49 -0400220
Jonathan Ballet648875f2011-07-16 14:14:58 +0900221 :param containee: the value that should be in :py:class:`container`
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900222 :param container: a sequence type, or in the case of a mapping type,
Jean-Paul Calderone060a57e2011-05-04 18:02:49 -0400223 will follow semantics of 'if key in dict.keys()'
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900224 :param msg: if msg is None, then the failure message will be
Jean-Paul Calderone060a57e2011-05-04 18:02:49 -0400225 '%r not in %r' % (first, second)
226 """
Alex Gaynord0e83ad2015-09-05 13:19:43 -0400227 assert containee in container
Jean-Paul Calderone060a57e2011-05-04 18:02:49 -0400228 assertIn = failUnlessIn
229
Jean-Paul Calderone15f36442014-05-01 07:58:02 -0400230 def assertNotIn(self, containee, container, msg=None):
231 """
232 Fail the test if C{containee} is found in C{container}.
233
234 @param containee: the value that should not be in C{container}
235 @param container: a sequence type, or in the case of a mapping type,
236 will follow semantics of 'if key in dict.keys()'
237 @param msg: if msg is None, then the failure message will be
238 '%r in %r' % (first, second)
239 """
Alex Gaynord0e83ad2015-09-05 13:19:43 -0400240 assert containee not in container
Jean-Paul Calderone15f36442014-05-01 07:58:02 -0400241 failIfIn = assertNotIn
242
Jean-Paul Calderone77b3d082014-12-12 20:04:35 -0500243 def assertIs(self, first, second, msg=None):
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400244 """
Jonathan Ballet648875f2011-07-16 14:14:58 +0900245 Fail the test if :py:data:`first` is not :py:data:`second`. This is an
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400246 obect-identity-equality test, not an object equality
Jonathan Ballet648875f2011-07-16 14:14:58 +0900247 (i.e. :py:func:`__eq__`) test.
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400248
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900249 :param msg: if msg is None, then the failure message will be
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400250 '%r is not %r' % (first, second)
251 """
Alex Gaynord0e83ad2015-09-05 13:19:43 -0400252 assert first is second
Jean-Paul Calderone77b3d082014-12-12 20:04:35 -0500253 assertIdentical = failUnlessIdentical = assertIs
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400254
Jean-Paul Calderone77b3d082014-12-12 20:04:35 -0500255 def assertIsNot(self, first, second, msg=None):
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400256 """
Jonathan Ballet648875f2011-07-16 14:14:58 +0900257 Fail the test if :py:data:`first` is :py:data:`second`. This is an
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400258 obect-identity-equality test, not an object equality
Jonathan Ballet648875f2011-07-16 14:14:58 +0900259 (i.e. :py:func:`__eq__`) test.
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400260
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900261 :param msg: if msg is None, then the failure message will be
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400262 '%r is %r' % (first, second)
263 """
Alex Gaynord0e83ad2015-09-05 13:19:43 -0400264 assert first is not second
Jean-Paul Calderone77b3d082014-12-12 20:04:35 -0500265 assertNotIdentical = failIfIdentical = assertIsNot
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400266
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400267 def failUnlessRaises(self, exception, f, *args, **kwargs):
268 """
Jonathan Ballet648875f2011-07-16 14:14:58 +0900269 Fail the test unless calling the function :py:data:`f` with the given
270 :py:data:`args` and :py:data:`kwargs` raises :py:data:`exception`. The
271 failure will report the traceback and call stack of the unexpected
272 exception.
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400273
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900274 :param exception: exception type that is to be expected
275 :param f: the function to call
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400276
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900277 :return: The raised exception instance, if it is of the given type.
278 :raise self.failureException: Raised if the function call does
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400279 not raise an exception or if it raises an exception of a
280 different type.
281 """
Alex Gaynord0e83ad2015-09-05 13:19:43 -0400282 with pytest.raises(exception) as cm:
283 f(*args, **kwargs)
284 return cm.value
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400285 assertRaises = failUnlessRaises
286
Hynek Schlawack4813c0e2015-04-16 13:38:01 -0400287 def mktemp(self):
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400288 """
Hynek Schlawack4813c0e2015-04-16 13:38:01 -0400289 Return UTF-8-encoded bytes of a path to a tmp file.
290
291 The file will be cleaned up after the test run.
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400292 """
Hynek Schlawack4813c0e2015-04-16 13:38:01 -0400293 return mktemp(dir=self.tmpdir).encode("utf-8")
Jean-Paul Calderone0ef63ed2009-07-05 13:05:45 -0400294
Jean-Paul Calderone68649052009-07-17 21:14:27 -0400295 # Other stuff
296 def assertConsistentType(self, theType, name, *constructionArgs):
297 """
Alex Gaynorc88f6282015-09-05 15:32:39 -0400298 Perform various assertions about :py:data:`theType` to ensure that it
299 is a well-defined type. This is useful for extension types, where it's
Jean-Paul Calderone68649052009-07-17 21:14:27 -0400300 pretty easy to do something wacky. If something about the type is
301 unusual, an exception will be raised.
302
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900303 :param theType: The type object about which to make assertions.
304 :param name: A string giving the name of the type.
Alex Gaynorc88f6282015-09-05 15:32:39 -0400305 :param constructionArgs: Positional arguments to use with
306 :py:data:`theType` to create an instance of it.
Jean-Paul Calderone68649052009-07-17 21:14:27 -0400307 """
Alex Chanc6077062016-11-18 13:53:39 +0000308 assert is_consistent_type(theType, name, *constructionArgs)
309
310
311def is_consistent_type(theType, name, *constructionArgs):
312 """
313 Perform various assertions about *theType* to ensure that it is a
314 well-defined type. This is useful for extension types, where it's
315 pretty easy to do something wacky. If something about the type is
316 unusual, an exception will be raised.
317
318 :param theType: The type object about which to make assertions.
319 :param name: A string giving the name of the type.
320 :param constructionArgs: Positional arguments to use with
321 *theType* to create an instance of it.
322 """
323 assert theType.__name__ == name
324 assert isinstance(theType, type)
325 instance = theType(*constructionArgs)
326 assert type(instance) is theType
327 return True
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400328
329
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400330class EqualityTestsMixin(object):
331 """
332 A mixin defining tests for the standard implementation of C{==} and C{!=}.
333 """
Alex Gaynorc88f6282015-09-05 15:32:39 -0400334
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400335 def anInstance(self):
336 """
337 Return an instance of the class under test. Each call to this method
338 must return a different object. All objects returned must be equal to
339 each other.
340 """
341 raise NotImplementedError()
342
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400343 def anotherInstance(self):
344 """
345 Return an instance of the class under test. Each call to this method
346 must return a different object. The objects must not be equal to the
347 objects returned by C{anInstance}. They may or may not be equal to
348 each other (they will not be compared against each other).
349 """
350 raise NotImplementedError()
351
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400352 def test_identicalEq(self):
353 """
354 An object compares equal to itself using the C{==} operator.
355 """
356 o = self.anInstance()
357 self.assertTrue(o == o)
358
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400359 def test_identicalNe(self):
360 """
361 An object doesn't compare not equal to itself using the C{!=} operator.
362 """
363 o = self.anInstance()
364 self.assertFalse(o != o)
365
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400366 def test_sameEq(self):
367 """
368 Two objects that are equal to each other compare equal to each other
369 using the C{==} operator.
370 """
371 a = self.anInstance()
372 b = self.anInstance()
373 self.assertTrue(a == b)
374
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400375 def test_sameNe(self):
376 """
377 Two objects that are equal to each other do not compare not equal to
378 each other using the C{!=} operator.
379 """
380 a = self.anInstance()
381 b = self.anInstance()
382 self.assertFalse(a != b)
383
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400384 def test_differentEq(self):
385 """
386 Two objects that are not equal to each other do not compare equal to
387 each other using the C{==} operator.
388 """
389 a = self.anInstance()
390 b = self.anotherInstance()
391 self.assertFalse(a == b)
392
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400393 def test_differentNe(self):
394 """
395 Two objects that are not equal to each other compare not equal to each
396 other using the C{!=} operator.
397 """
398 a = self.anInstance()
399 b = self.anotherInstance()
400 self.assertTrue(a != b)
401
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400402 def test_anotherTypeEq(self):
403 """
404 The object does not compare equal to an object of an unrelated type
405 (which does not implement the comparison) using the C{==} operator.
406 """
407 a = self.anInstance()
408 b = object()
409 self.assertFalse(a == b)
410
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400411 def test_anotherTypeNe(self):
412 """
413 The object compares not equal to an object of an unrelated type (which
414 does not implement the comparison) using the C{!=} operator.
415 """
416 a = self.anInstance()
417 b = object()
418 self.assertTrue(a != b)
419
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400420 def test_delegatedEq(self):
421 """
422 The result of comparison using C{==} is delegated to the right-hand
423 operand if it is of an unrelated type.
424 """
425 class Delegate(object):
426 def __eq__(self, other):
427 # Do something crazy and obvious.
428 return [self]
429
430 a = self.anInstance()
431 b = Delegate()
432 self.assertEqual(a == b, [b])
433
Jean-Paul Calderone9c7f0692014-04-30 18:17:19 -0400434 def test_delegateNe(self):
435 """
436 The result of comparison using C{!=} is delegated to the right-hand
437 operand if it is of an unrelated type.
438 """
439 class Delegate(object):
440 def __ne__(self, other):
441 # Do something crazy and obvious.
442 return [self]
443
444 a = self.anInstance()
445 b = Delegate()
446 self.assertEqual(a != b, [b])
Jean-Paul Calderone6462b072015-03-29 07:03:11 -0400447
448
449# The type name expected in warnings about using the wrong string type.
450if PY3:
451 WARNING_TYPE_EXPECTED = "str"
452else:
453 WARNING_TYPE_EXPECTED = "unicode"