blob: f8f3717b641e1cae8edfd57259ff63d050e26153 [file] [log] [blame]
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +00001# Tests for rich comparisons
2
Walter Dörwald721adf92003-04-29 21:31:19 +00003import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004from test import support
Walter Dörwald721adf92003-04-29 21:31:19 +00005
6import operator
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +00007
8class Number:
9
10 def __init__(self, x):
11 self.x = x
12
13 def __lt__(self, other):
14 return self.x < other
15
16 def __le__(self, other):
17 return self.x <= other
18
19 def __eq__(self, other):
20 return self.x == other
21
22 def __ne__(self, other):
23 return self.x != other
24
25 def __gt__(self, other):
26 return self.x > other
27
28 def __ge__(self, other):
29 return self.x >= other
30
31 def __cmp__(self, other):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000032 raise support.TestFailed("Number.__cmp__() should not be called")
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +000033
34 def __repr__(self):
Walter Dörwald721adf92003-04-29 21:31:19 +000035 return "Number(%r)" % (self.x, )
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +000036
37class Vector:
38
39 def __init__(self, data):
40 self.data = data
41
42 def __len__(self):
43 return len(self.data)
44
45 def __getitem__(self, i):
46 return self.data[i]
47
48 def __setitem__(self, i, v):
49 self.data[i] = v
50
Nick Coghland1abd252008-07-15 15:46:38 +000051 __hash__ = None # Vectors cannot be hashed
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +000052
Jack Diederich4dafcc42006-11-28 19:15:13 +000053 def __bool__(self):
Collin Winter3add4d72007-08-29 23:37:32 +000054 raise TypeError("Vectors cannot be used in Boolean contexts")
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +000055
56 def __cmp__(self, other):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000057 raise support.TestFailed("Vector.__cmp__() should not be called")
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +000058
59 def __repr__(self):
Walter Dörwald721adf92003-04-29 21:31:19 +000060 return "Vector(%r)" % (self.data, )
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +000061
62 def __lt__(self, other):
63 return Vector([a < b for a, b in zip(self.data, self.__cast(other))])
64
65 def __le__(self, other):
66 return Vector([a <= b for a, b in zip(self.data, self.__cast(other))])
67
68 def __eq__(self, other):
69 return Vector([a == b for a, b in zip(self.data, self.__cast(other))])
70
71 def __ne__(self, other):
72 return Vector([a != b for a, b in zip(self.data, self.__cast(other))])
73
74 def __gt__(self, other):
75 return Vector([a > b for a, b in zip(self.data, self.__cast(other))])
76
77 def __ge__(self, other):
78 return Vector([a >= b for a, b in zip(self.data, self.__cast(other))])
79
80 def __cast(self, other):
81 if isinstance(other, Vector):
82 other = other.data
83 if len(self.data) != len(other):
Collin Winter3add4d72007-08-29 23:37:32 +000084 raise ValueError("Cannot compare vectors of different length")
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +000085 return other
86
Walter Dörwald721adf92003-04-29 21:31:19 +000087opmap = {
88 "lt": (lambda a,b: a< b, operator.lt, operator.__lt__),
89 "le": (lambda a,b: a<=b, operator.le, operator.__le__),
90 "eq": (lambda a,b: a==b, operator.eq, operator.__eq__),
91 "ne": (lambda a,b: a!=b, operator.ne, operator.__ne__),
92 "gt": (lambda a,b: a> b, operator.gt, operator.__gt__),
93 "ge": (lambda a,b: a>=b, operator.ge, operator.__ge__)
94}
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +000095
Walter Dörwald721adf92003-04-29 21:31:19 +000096class VectorTest(unittest.TestCase):
97
98 def checkfail(self, error, opname, *args):
99 for op in opmap[opname]:
100 self.assertRaises(error, op, *args)
101
102 def checkequal(self, opname, a, b, expres):
103 for op in opmap[opname]:
104 realres = op(a, b)
105 # can't use assertEqual(realres, expres) here
106 self.assertEqual(len(realres), len(expres))
Guido van Rossum805365e2007-05-07 22:24:25 +0000107 for i in range(len(realres)):
Walter Dörwald721adf92003-04-29 21:31:19 +0000108 # results are bool, so we can use "is" here
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000109 self.assertTrue(realres[i] is expres[i])
Walter Dörwald721adf92003-04-29 21:31:19 +0000110
111 def test_mixed(self):
112 # check that comparisons involving Vector objects
113 # which return rich results (i.e. Vectors with itemwise
114 # comparison results) work
115 a = Vector(range(2))
116 b = Vector(range(3))
117 # all comparisons should fail for different length
118 for opname in opmap:
119 self.checkfail(ValueError, opname, a, b)
120
Guido van Rossum805365e2007-05-07 22:24:25 +0000121 a = list(range(5))
Walter Dörwald721adf92003-04-29 21:31:19 +0000122 b = 5 * [2]
123 # try mixed arguments (but not (a, b) as that won't return a bool vector)
124 args = [(a, Vector(b)), (Vector(a), b), (Vector(a), Vector(b))]
125 for (a, b) in args:
126 self.checkequal("lt", a, b, [True, True, False, False, False])
127 self.checkequal("le", a, b, [True, True, True, False, False])
128 self.checkequal("eq", a, b, [False, False, True, False, False])
129 self.checkequal("ne", a, b, [True, True, False, True, True ])
130 self.checkequal("gt", a, b, [False, False, False, True, True ])
131 self.checkequal("ge", a, b, [False, False, True, True, True ])
132
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000133 for ops in opmap.values():
Walter Dörwald721adf92003-04-29 21:31:19 +0000134 for op in ops:
Jack Diederich4dafcc42006-11-28 19:15:13 +0000135 # calls __bool__, which should fail
Walter Dörwald721adf92003-04-29 21:31:19 +0000136 self.assertRaises(TypeError, bool, op(a, b))
137
138class NumberTest(unittest.TestCase):
139
140 def test_basic(self):
141 # Check that comparisons involving Number objects
142 # give the same results give as comparing the
143 # corresponding ints
Guido van Rossum805365e2007-05-07 22:24:25 +0000144 for a in range(3):
145 for b in range(3):
Walter Dörwald721adf92003-04-29 21:31:19 +0000146 for typea in (int, Number):
147 for typeb in (int, Number):
148 if typea==typeb==int:
149 continue # the combination int, int is useless
150 ta = typea(a)
151 tb = typeb(b)
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000152 for ops in opmap.values():
Walter Dörwald721adf92003-04-29 21:31:19 +0000153 for op in ops:
154 realoutcome = op(a, b)
155 testoutcome = op(ta, tb)
156 self.assertEqual(realoutcome, testoutcome)
157
158 def checkvalue(self, opname, a, b, expres):
159 for typea in (int, Number):
160 for typeb in (int, Number):
161 ta = typea(a)
162 tb = typeb(b)
163 for op in opmap[opname]:
164 realres = op(ta, tb)
165 realres = getattr(realres, "x", realres)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000166 self.assertTrue(realres is expres)
Walter Dörwald721adf92003-04-29 21:31:19 +0000167
168 def test_values(self):
169 # check all operators and all comparison results
170 self.checkvalue("lt", 0, 0, False)
171 self.checkvalue("le", 0, 0, True )
172 self.checkvalue("eq", 0, 0, True )
173 self.checkvalue("ne", 0, 0, False)
174 self.checkvalue("gt", 0, 0, False)
175 self.checkvalue("ge", 0, 0, True )
176
177 self.checkvalue("lt", 0, 1, True )
178 self.checkvalue("le", 0, 1, True )
179 self.checkvalue("eq", 0, 1, False)
180 self.checkvalue("ne", 0, 1, True )
181 self.checkvalue("gt", 0, 1, False)
182 self.checkvalue("ge", 0, 1, False)
183
184 self.checkvalue("lt", 1, 0, False)
185 self.checkvalue("le", 1, 0, False)
186 self.checkvalue("eq", 1, 0, False)
187 self.checkvalue("ne", 1, 0, True )
188 self.checkvalue("gt", 1, 0, True )
189 self.checkvalue("ge", 1, 0, True )
190
191class MiscTest(unittest.TestCase):
192
193 def test_misbehavin(self):
194 class Misb:
Georg Brandl89fad142010-03-14 10:23:39 +0000195 def __lt__(self_, other): return 0
196 def __gt__(self_, other): return 0
197 def __eq__(self_, other): return 0
198 def __le__(self_, other): self.fail("This shouldn't happen")
199 def __ge__(self_, other): self.fail("This shouldn't happen")
200 def __ne__(self_, other): self.fail("This shouldn't happen")
Walter Dörwald721adf92003-04-29 21:31:19 +0000201 a = Misb()
202 b = Misb()
203 self.assertEqual(a<b, 0)
204 self.assertEqual(a==b, 0)
205 self.assertEqual(a>b, 0)
Walter Dörwald721adf92003-04-29 21:31:19 +0000206
207 def test_not(self):
Jack Diederich4dafcc42006-11-28 19:15:13 +0000208 # Check that exceptions in __bool__ are properly
Walter Dörwald721adf92003-04-29 21:31:19 +0000209 # propagated by the not operator
210 import operator
Neal Norwitz0fb43762006-03-24 07:02:16 +0000211 class Exc(Exception):
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +0000212 pass
Walter Dörwald721adf92003-04-29 21:31:19 +0000213 class Bad:
Jack Diederich4dafcc42006-11-28 19:15:13 +0000214 def __bool__(self):
Walter Dörwald721adf92003-04-29 21:31:19 +0000215 raise Exc
216
217 def do(bad):
218 not bad
219
220 for func in (do, operator.not_):
221 self.assertRaises(Exc, func, Bad())
222
223 def test_recursion(self):
Armin Rigo2b3eb402003-10-28 12:05:48 +0000224 # Check that comparison for recursive objects fails gracefully
Raymond Hettinger53dbe392008-02-12 20:03:09 +0000225 from collections import UserList
Walter Dörwald721adf92003-04-29 21:31:19 +0000226 a = UserList()
227 b = UserList()
228 a.append(b)
229 b.append(a)
Armin Rigo2b3eb402003-10-28 12:05:48 +0000230 self.assertRaises(RuntimeError, operator.eq, a, b)
231 self.assertRaises(RuntimeError, operator.ne, a, b)
232 self.assertRaises(RuntimeError, operator.lt, a, b)
233 self.assertRaises(RuntimeError, operator.le, a, b)
234 self.assertRaises(RuntimeError, operator.gt, a, b)
235 self.assertRaises(RuntimeError, operator.ge, a, b)
Walter Dörwald721adf92003-04-29 21:31:19 +0000236
237 b.append(17)
Armin Rigo2b3eb402003-10-28 12:05:48 +0000238 # Even recursive lists of different lengths are different,
239 # but they cannot be ordered
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000240 self.assertTrue(not (a == b))
241 self.assertTrue(a != b)
Armin Rigo2b3eb402003-10-28 12:05:48 +0000242 self.assertRaises(RuntimeError, operator.lt, a, b)
243 self.assertRaises(RuntimeError, operator.le, a, b)
244 self.assertRaises(RuntimeError, operator.gt, a, b)
245 self.assertRaises(RuntimeError, operator.ge, a, b)
Walter Dörwald721adf92003-04-29 21:31:19 +0000246 a.append(17)
Armin Rigo2b3eb402003-10-28 12:05:48 +0000247 self.assertRaises(RuntimeError, operator.eq, a, b)
248 self.assertRaises(RuntimeError, operator.ne, a, b)
249 a.insert(0, 11)
250 b.insert(0, 12)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000251 self.assertTrue(not (a == b))
252 self.assertTrue(a != b)
253 self.assertTrue(a < b)
Walter Dörwald721adf92003-04-29 21:31:19 +0000254
255class DictTest(unittest.TestCase):
256
257 def test_dicts(self):
258 # Verify that __eq__ and __ne__ work for dicts even if the keys and
Georg Brandlbe3856d2005-08-24 09:08:57 +0000259 # values don't support anything other than __eq__ and __ne__ (and
260 # __hash__). Complex numbers are a fine example of that.
Walter Dörwald721adf92003-04-29 21:31:19 +0000261 import random
262 imag1a = {}
263 for i in range(50):
264 imag1a[random.randrange(100)*1j] = random.randrange(100)*1j
Guido van Rossum75d26cc2007-02-15 04:01:01 +0000265 items = list(imag1a.items())
Walter Dörwald721adf92003-04-29 21:31:19 +0000266 random.shuffle(items)
267 imag1b = {}
268 for k, v in items:
269 imag1b[k] = v
270 imag2 = imag1b.copy()
271 imag2[k] = v + 1.0
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000272 self.assertEqual(imag1a, imag1a)
273 self.assertEqual(imag1a, imag1b)
274 self.assertEqual(imag2, imag2)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000275 self.assertTrue(imag1a != imag2)
Walter Dörwald721adf92003-04-29 21:31:19 +0000276 for opname in ("lt", "le", "gt", "ge"):
277 for op in opmap[opname]:
278 self.assertRaises(TypeError, op, imag1a, imag2)
279
280class ListTest(unittest.TestCase):
281
Walter Dörwald721adf92003-04-29 21:31:19 +0000282 def test_coverage(self):
283 # exercise all comparisons for lists
284 x = [42]
285 self.assertIs(x<x, False)
286 self.assertIs(x<=x, True)
287 self.assertIs(x==x, True)
288 self.assertIs(x!=x, False)
289 self.assertIs(x>x, False)
290 self.assertIs(x>=x, True)
291 y = [42, 42]
292 self.assertIs(x<y, True)
293 self.assertIs(x<=y, True)
294 self.assertIs(x==y, False)
295 self.assertIs(x!=y, True)
296 self.assertIs(x>y, False)
297 self.assertIs(x>=y, False)
298
299 def test_badentry(self):
300 # make sure that exceptions for item comparison are properly
301 # propagated in list comparisons
Neal Norwitz0fb43762006-03-24 07:02:16 +0000302 class Exc(Exception):
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +0000303 pass
Walter Dörwald721adf92003-04-29 21:31:19 +0000304 class Bad:
305 def __eq__(self, other):
306 raise Exc
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +0000307
Walter Dörwald721adf92003-04-29 21:31:19 +0000308 x = [Bad()]
309 y = [Bad()]
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +0000310
Walter Dörwald721adf92003-04-29 21:31:19 +0000311 for op in opmap["eq"]:
312 self.assertRaises(Exc, op, x, y)
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +0000313
Walter Dörwald721adf92003-04-29 21:31:19 +0000314 def test_goodentry(self):
315 # This test exercises the final call to PyObject_RichCompare()
316 # in Objects/listobject.c::list_richcompare()
317 class Good:
318 def __lt__(self, other):
319 return True
Guido van Rossumc4a6e8b2001-01-18 15:48:05 +0000320
Walter Dörwald721adf92003-04-29 21:31:19 +0000321 x = [Good()]
322 y = [Good()]
Tim Peters8880f6d2001-01-19 06:12:17 +0000323
Walter Dörwald721adf92003-04-29 21:31:19 +0000324 for op in opmap["lt"]:
325 self.assertIs(op(x, y), True)
Guido van Rossum9710bd52001-01-18 15:55:59 +0000326
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000327
Walter Dörwald721adf92003-04-29 21:31:19 +0000328def test_main():
Nick Coghland1abd252008-07-15 15:46:38 +0000329 support.run_unittest(VectorTest, NumberTest, MiscTest, DictTest, ListTest)
Guido van Rossum890f2092001-01-18 16:21:57 +0000330
Walter Dörwald721adf92003-04-29 21:31:19 +0000331if __name__ == "__main__":
332 test_main()