1 """Test equality and order comparisons."""
2 import unittest
3 from test.support import ALWAYS_EQ
4 from fractions import Fraction
5 from decimal import Decimal
6
7
8 class ESC[4;38;5;81mComparisonSimpleTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
9 """Test equality and order comparisons for some simple cases."""
10
11 class ESC[4;38;5;81mEmpty:
12 def __repr__(self):
13 return '<Empty>'
14
15 class ESC[4;38;5;81mCmp:
16 def __init__(self, arg):
17 self.arg = arg
18
19 def __repr__(self):
20 return '<Cmp %s>' % self.arg
21
22 def __eq__(self, other):
23 return self.arg == other
24
25 set1 = [2, 2.0, 2, 2+0j, Cmp(2.0)]
26 set2 = [[1], (3,), None, Empty()]
27 candidates = set1 + set2
28
29 def test_comparisons(self):
30 for a in self.candidates:
31 for b in self.candidates:
32 if ((a in self.set1) and (b in self.set1)) or a is b:
33 self.assertEqual(a, b)
34 else:
35 self.assertNotEqual(a, b)
36
37 def test_id_comparisons(self):
38 # Ensure default comparison compares id() of args
39 L = []
40 for i in range(10):
41 L.insert(len(L)//2, self.Empty())
42 for a in L:
43 for b in L:
44 self.assertEqual(a == b, a is b, 'a=%r, b=%r' % (a, b))
45
46 def test_ne_defaults_to_not_eq(self):
47 a = self.Cmp(1)
48 b = self.Cmp(1)
49 c = self.Cmp(2)
50 self.assertIs(a == b, True)
51 self.assertIs(a != b, False)
52 self.assertIs(a != c, True)
53
54 def test_ne_high_priority(self):
55 """object.__ne__() should allow reflected __ne__() to be tried"""
56 calls = []
57 class ESC[4;38;5;81mLeft:
58 # Inherits object.__ne__()
59 def __eq__(*args):
60 calls.append('Left.__eq__')
61 return NotImplemented
62 class ESC[4;38;5;81mRight:
63 def __eq__(*args):
64 calls.append('Right.__eq__')
65 return NotImplemented
66 def __ne__(*args):
67 calls.append('Right.__ne__')
68 return NotImplemented
69 Left() != Right()
70 self.assertSequenceEqual(calls, ['Left.__eq__', 'Right.__ne__'])
71
72 def test_ne_low_priority(self):
73 """object.__ne__() should not invoke reflected __eq__()"""
74 calls = []
75 class ESC[4;38;5;81mBase:
76 # Inherits object.__ne__()
77 def __eq__(*args):
78 calls.append('Base.__eq__')
79 return NotImplemented
80 class ESC[4;38;5;81mDerived(ESC[4;38;5;149mBase): # Subclassing forces higher priority
81 def __eq__(*args):
82 calls.append('Derived.__eq__')
83 return NotImplemented
84 def __ne__(*args):
85 calls.append('Derived.__ne__')
86 return NotImplemented
87 Base() != Derived()
88 self.assertSequenceEqual(calls, ['Derived.__ne__', 'Base.__eq__'])
89
90 def test_other_delegation(self):
91 """No default delegation between operations except __ne__()"""
92 ops = (
93 ('__eq__', lambda a, b: a == b),
94 ('__lt__', lambda a, b: a < b),
95 ('__le__', lambda a, b: a <= b),
96 ('__gt__', lambda a, b: a > b),
97 ('__ge__', lambda a, b: a >= b),
98 )
99 for name, func in ops:
100 with self.subTest(name):
101 def unexpected(*args):
102 self.fail('Unexpected operator method called')
103 class ESC[4;38;5;81mC:
104 __ne__ = unexpected
105 for other, _ in ops:
106 if other != name:
107 setattr(C, other, unexpected)
108 if name == '__eq__':
109 self.assertIs(func(C(), object()), False)
110 else:
111 self.assertRaises(TypeError, func, C(), object())
112
113 def test_issue_1393(self):
114 x = lambda: None
115 self.assertEqual(x, ALWAYS_EQ)
116 self.assertEqual(ALWAYS_EQ, x)
117 y = object()
118 self.assertEqual(y, ALWAYS_EQ)
119 self.assertEqual(ALWAYS_EQ, y)
120
121
122 class ESC[4;38;5;81mComparisonFullTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
123 """Test equality and ordering comparisons for built-in types and
124 user-defined classes that implement relevant combinations of rich
125 comparison methods.
126 """
127
128 class ESC[4;38;5;81mCompBase:
129 """Base class for classes with rich comparison methods.
130
131 The "x" attribute should be set to an underlying value to compare.
132
133 Derived classes have a "meth" tuple attribute listing names of
134 comparison methods implemented. See assert_total_order().
135 """
136
137 # Class without any rich comparison methods.
138 class ESC[4;38;5;81mCompNone(ESC[4;38;5;149mCompBase):
139 meth = ()
140
141 # Classes with all combinations of value-based equality comparison methods.
142 class ESC[4;38;5;81mCompEq(ESC[4;38;5;149mCompBase):
143 meth = ("eq",)
144 def __eq__(self, other):
145 return self.x == other.x
146
147 class ESC[4;38;5;81mCompNe(ESC[4;38;5;149mCompBase):
148 meth = ("ne",)
149 def __ne__(self, other):
150 return self.x != other.x
151
152 class ESC[4;38;5;81mCompEqNe(ESC[4;38;5;149mCompBase):
153 meth = ("eq", "ne")
154 def __eq__(self, other):
155 return self.x == other.x
156 def __ne__(self, other):
157 return self.x != other.x
158
159 # Classes with all combinations of value-based less/greater-than order
160 # comparison methods.
161 class ESC[4;38;5;81mCompLt(ESC[4;38;5;149mCompBase):
162 meth = ("lt",)
163 def __lt__(self, other):
164 return self.x < other.x
165
166 class ESC[4;38;5;81mCompGt(ESC[4;38;5;149mCompBase):
167 meth = ("gt",)
168 def __gt__(self, other):
169 return self.x > other.x
170
171 class ESC[4;38;5;81mCompLtGt(ESC[4;38;5;149mCompBase):
172 meth = ("lt", "gt")
173 def __lt__(self, other):
174 return self.x < other.x
175 def __gt__(self, other):
176 return self.x > other.x
177
178 # Classes with all combinations of value-based less/greater-or-equal-than
179 # order comparison methods
180 class ESC[4;38;5;81mCompLe(ESC[4;38;5;149mCompBase):
181 meth = ("le",)
182 def __le__(self, other):
183 return self.x <= other.x
184
185 class ESC[4;38;5;81mCompGe(ESC[4;38;5;149mCompBase):
186 meth = ("ge",)
187 def __ge__(self, other):
188 return self.x >= other.x
189
190 class ESC[4;38;5;81mCompLeGe(ESC[4;38;5;149mCompBase):
191 meth = ("le", "ge")
192 def __le__(self, other):
193 return self.x <= other.x
194 def __ge__(self, other):
195 return self.x >= other.x
196
197 # It should be sufficient to combine the comparison methods only within
198 # each group.
199 all_comp_classes = (
200 CompNone,
201 CompEq, CompNe, CompEqNe, # equal group
202 CompLt, CompGt, CompLtGt, # less/greater-than group
203 CompLe, CompGe, CompLeGe) # less/greater-or-equal group
204
205 def create_sorted_instances(self, class_, values):
206 """Create objects of type `class_` and return them in a list.
207
208 `values` is a list of values that determines the value of data
209 attribute `x` of each object.
210
211 Objects in the returned list are sorted by their identity. They
212 assigned values in `values` list order. By assign decreasing
213 values to objects with increasing identities, testcases can assert
214 that order comparison is performed by value and not by identity.
215 """
216
217 instances = [class_() for __ in range(len(values))]
218 instances.sort(key=id)
219 # Assign the provided values to the instances.
220 for inst, value in zip(instances, values):
221 inst.x = value
222 return instances
223
224 def assert_equality_only(self, a, b, equal):
225 """Assert equality result and that ordering is not implemented.
226
227 a, b: Instances to be tested (of same or different type).
228 equal: Boolean indicating the expected equality comparison results.
229 """
230 self.assertEqual(a == b, equal)
231 self.assertEqual(b == a, equal)
232 self.assertEqual(a != b, not equal)
233 self.assertEqual(b != a, not equal)
234 with self.assertRaisesRegex(TypeError, "not supported"):
235 a < b
236 with self.assertRaisesRegex(TypeError, "not supported"):
237 a <= b
238 with self.assertRaisesRegex(TypeError, "not supported"):
239 a > b
240 with self.assertRaisesRegex(TypeError, "not supported"):
241 a >= b
242 with self.assertRaisesRegex(TypeError, "not supported"):
243 b < a
244 with self.assertRaisesRegex(TypeError, "not supported"):
245 b <= a
246 with self.assertRaisesRegex(TypeError, "not supported"):
247 b > a
248 with self.assertRaisesRegex(TypeError, "not supported"):
249 b >= a
250
251 def assert_total_order(self, a, b, comp, a_meth=None, b_meth=None):
252 """Test total ordering comparison of two instances.
253
254 a, b: Instances to be tested (of same or different type).
255
256 comp: -1, 0, or 1 indicates that the expected order comparison
257 result for operations that are supported by the classes is
258 a <, ==, or > b.
259
260 a_meth, b_meth: Either None, indicating that all rich comparison
261 methods are available, aa for builtins, or the tuple (subset)
262 of "eq", "ne", "lt", "le", "gt", and "ge" that are available
263 for the corresponding instance (of a user-defined class).
264 """
265 self.assert_eq_subtest(a, b, comp, a_meth, b_meth)
266 self.assert_ne_subtest(a, b, comp, a_meth, b_meth)
267 self.assert_lt_subtest(a, b, comp, a_meth, b_meth)
268 self.assert_le_subtest(a, b, comp, a_meth, b_meth)
269 self.assert_gt_subtest(a, b, comp, a_meth, b_meth)
270 self.assert_ge_subtest(a, b, comp, a_meth, b_meth)
271
272 # The body of each subtest has form:
273 #
274 # if value-based comparison methods:
275 # expect what the testcase defined for a op b and b rop a;
276 # else: no value-based comparison
277 # expect default behavior of object for a op b and b rop a.
278
279 def assert_eq_subtest(self, a, b, comp, a_meth, b_meth):
280 if a_meth is None or "eq" in a_meth or "eq" in b_meth:
281 self.assertEqual(a == b, comp == 0)
282 self.assertEqual(b == a, comp == 0)
283 else:
284 self.assertEqual(a == b, a is b)
285 self.assertEqual(b == a, a is b)
286
287 def assert_ne_subtest(self, a, b, comp, a_meth, b_meth):
288 if a_meth is None or not {"ne", "eq"}.isdisjoint(a_meth + b_meth):
289 self.assertEqual(a != b, comp != 0)
290 self.assertEqual(b != a, comp != 0)
291 else:
292 self.assertEqual(a != b, a is not b)
293 self.assertEqual(b != a, a is not b)
294
295 def assert_lt_subtest(self, a, b, comp, a_meth, b_meth):
296 if a_meth is None or "lt" in a_meth or "gt" in b_meth:
297 self.assertEqual(a < b, comp < 0)
298 self.assertEqual(b > a, comp < 0)
299 else:
300 with self.assertRaisesRegex(TypeError, "not supported"):
301 a < b
302 with self.assertRaisesRegex(TypeError, "not supported"):
303 b > a
304
305 def assert_le_subtest(self, a, b, comp, a_meth, b_meth):
306 if a_meth is None or "le" in a_meth or "ge" in b_meth:
307 self.assertEqual(a <= b, comp <= 0)
308 self.assertEqual(b >= a, comp <= 0)
309 else:
310 with self.assertRaisesRegex(TypeError, "not supported"):
311 a <= b
312 with self.assertRaisesRegex(TypeError, "not supported"):
313 b >= a
314
315 def assert_gt_subtest(self, a, b, comp, a_meth, b_meth):
316 if a_meth is None or "gt" in a_meth or "lt" in b_meth:
317 self.assertEqual(a > b, comp > 0)
318 self.assertEqual(b < a, comp > 0)
319 else:
320 with self.assertRaisesRegex(TypeError, "not supported"):
321 a > b
322 with self.assertRaisesRegex(TypeError, "not supported"):
323 b < a
324
325 def assert_ge_subtest(self, a, b, comp, a_meth, b_meth):
326 if a_meth is None or "ge" in a_meth or "le" in b_meth:
327 self.assertEqual(a >= b, comp >= 0)
328 self.assertEqual(b <= a, comp >= 0)
329 else:
330 with self.assertRaisesRegex(TypeError, "not supported"):
331 a >= b
332 with self.assertRaisesRegex(TypeError, "not supported"):
333 b <= a
334
335 def test_objects(self):
336 """Compare instances of type 'object'."""
337 a = object()
338 b = object()
339 self.assert_equality_only(a, a, True)
340 self.assert_equality_only(a, b, False)
341
342 def test_comp_classes_same(self):
343 """Compare same-class instances with comparison methods."""
344
345 for cls in self.all_comp_classes:
346 with self.subTest(cls):
347 instances = self.create_sorted_instances(cls, (1, 2, 1))
348
349 # Same object.
350 self.assert_total_order(instances[0], instances[0], 0,
351 cls.meth, cls.meth)
352
353 # Different objects, same value.
354 self.assert_total_order(instances[0], instances[2], 0,
355 cls.meth, cls.meth)
356
357 # Different objects, value ascending for ascending identities.
358 self.assert_total_order(instances[0], instances[1], -1,
359 cls.meth, cls.meth)
360
361 # different objects, value descending for ascending identities.
362 # This is the interesting case to assert that order comparison
363 # is performed based on the value and not based on the identity.
364 self.assert_total_order(instances[1], instances[2], +1,
365 cls.meth, cls.meth)
366
367 def test_comp_classes_different(self):
368 """Compare different-class instances with comparison methods."""
369
370 for cls_a in self.all_comp_classes:
371 for cls_b in self.all_comp_classes:
372 with self.subTest(a=cls_a, b=cls_b):
373 a1 = cls_a()
374 a1.x = 1
375 b1 = cls_b()
376 b1.x = 1
377 b2 = cls_b()
378 b2.x = 2
379
380 self.assert_total_order(
381 a1, b1, 0, cls_a.meth, cls_b.meth)
382 self.assert_total_order(
383 a1, b2, -1, cls_a.meth, cls_b.meth)
384
385 def test_str_subclass(self):
386 """Compare instances of str and a subclass."""
387 class ESC[4;38;5;81mStrSubclass(ESC[4;38;5;149mstr):
388 pass
389
390 s1 = str("a")
391 s2 = str("b")
392 c1 = StrSubclass("a")
393 c2 = StrSubclass("b")
394 c3 = StrSubclass("b")
395
396 self.assert_total_order(s1, s1, 0)
397 self.assert_total_order(s1, s2, -1)
398 self.assert_total_order(c1, c1, 0)
399 self.assert_total_order(c1, c2, -1)
400 self.assert_total_order(c2, c3, 0)
401
402 self.assert_total_order(s1, c2, -1)
403 self.assert_total_order(s2, c3, 0)
404 self.assert_total_order(c1, s2, -1)
405 self.assert_total_order(c2, s2, 0)
406
407 def test_numbers(self):
408 """Compare number types."""
409
410 # Same types.
411 i1 = 1001
412 i2 = 1002
413 self.assert_total_order(i1, i1, 0)
414 self.assert_total_order(i1, i2, -1)
415
416 f1 = 1001.0
417 f2 = 1001.1
418 self.assert_total_order(f1, f1, 0)
419 self.assert_total_order(f1, f2, -1)
420
421 q1 = Fraction(2002, 2)
422 q2 = Fraction(2003, 2)
423 self.assert_total_order(q1, q1, 0)
424 self.assert_total_order(q1, q2, -1)
425
426 d1 = Decimal('1001.0')
427 d2 = Decimal('1001.1')
428 self.assert_total_order(d1, d1, 0)
429 self.assert_total_order(d1, d2, -1)
430
431 c1 = 1001+0j
432 c2 = 1001+1j
433 self.assert_equality_only(c1, c1, True)
434 self.assert_equality_only(c1, c2, False)
435
436
437 # Mixing types.
438 for n1, n2 in ((i1,f1), (i1,q1), (i1,d1), (f1,q1), (f1,d1), (q1,d1)):
439 self.assert_total_order(n1, n2, 0)
440 for n1 in (i1, f1, q1, d1):
441 self.assert_equality_only(n1, c1, True)
442
443 def test_sequences(self):
444 """Compare list, tuple, and range."""
445 l1 = [1, 2]
446 l2 = [2, 3]
447 self.assert_total_order(l1, l1, 0)
448 self.assert_total_order(l1, l2, -1)
449
450 t1 = (1, 2)
451 t2 = (2, 3)
452 self.assert_total_order(t1, t1, 0)
453 self.assert_total_order(t1, t2, -1)
454
455 r1 = range(1, 2)
456 r2 = range(2, 2)
457 self.assert_equality_only(r1, r1, True)
458 self.assert_equality_only(r1, r2, False)
459
460 self.assert_equality_only(t1, l1, False)
461 self.assert_equality_only(l1, r1, False)
462 self.assert_equality_only(r1, t1, False)
463
464 def test_bytes(self):
465 """Compare bytes and bytearray."""
466 bs1 = b'a1'
467 bs2 = b'b2'
468 self.assert_total_order(bs1, bs1, 0)
469 self.assert_total_order(bs1, bs2, -1)
470
471 ba1 = bytearray(b'a1')
472 ba2 = bytearray(b'b2')
473 self.assert_total_order(ba1, ba1, 0)
474 self.assert_total_order(ba1, ba2, -1)
475
476 self.assert_total_order(bs1, ba1, 0)
477 self.assert_total_order(bs1, ba2, -1)
478 self.assert_total_order(ba1, bs1, 0)
479 self.assert_total_order(ba1, bs2, -1)
480
481 def test_sets(self):
482 """Compare set and frozenset."""
483 s1 = {1, 2}
484 s2 = {1, 2, 3}
485 self.assert_total_order(s1, s1, 0)
486 self.assert_total_order(s1, s2, -1)
487
488 f1 = frozenset(s1)
489 f2 = frozenset(s2)
490 self.assert_total_order(f1, f1, 0)
491 self.assert_total_order(f1, f2, -1)
492
493 self.assert_total_order(s1, f1, 0)
494 self.assert_total_order(s1, f2, -1)
495 self.assert_total_order(f1, s1, 0)
496 self.assert_total_order(f1, s2, -1)
497
498 def test_mappings(self):
499 """ Compare dict.
500 """
501 d1 = {1: "a", 2: "b"}
502 d2 = {2: "b", 3: "c"}
503 d3 = {3: "c", 2: "b"}
504 self.assert_equality_only(d1, d1, True)
505 self.assert_equality_only(d1, d2, False)
506 self.assert_equality_only(d2, d3, True)
507
508
509 if __name__ == '__main__':
510 unittest.main()