blob: c6a1c1763606aa3077da7f88ca19e0e12dccad44 [file] [log] [blame]
Neil Schemenauerfd288c72001-01-02 16:30:31 +00001import copy
Tim Petersf022a4d2002-04-15 23:52:04 +00002import warnings
Georg Brandl686eaeb2006-03-28 10:00:53 +00003import unittest
Brett Cannon5dc3e3f2006-06-13 22:26:13 +00004from test.test_support import run_unittest, TestFailed
Neil Schemenauerfd288c72001-01-02 16:30:31 +00005
6# Fake a number that implements numeric methods through __coerce__
7class CoerceNumber:
8 def __init__(self, arg):
9 self.arg = arg
10
11 def __repr__(self):
12 return '<CoerceNumber %s>' % repr(self.arg)
13
14 def __coerce__(self, other):
15 if isinstance(other, CoerceNumber):
16 return self.arg, other.arg
17 else:
18 return (self.arg, other)
19
Georg Brandl686eaeb2006-03-28 10:00:53 +000020# New-style class version of CoerceNumber
21class CoerceTo(object):
22 def __init__(self, arg):
23 self.arg = arg
24 def __coerce__(self, other):
25 if isinstance(other, CoerceTo):
26 return self.arg, other.arg
27 else:
28 return self.arg, other
29
Neil Schemenauerfd288c72001-01-02 16:30:31 +000030
31# Fake a number that implements numeric ops through methods.
32class MethodNumber:
Neil Schemenauerfd288c72001-01-02 16:30:31 +000033 def __init__(self,arg):
34 self.arg = arg
35
36 def __repr__(self):
37 return '<MethodNumber %s>' % repr(self.arg)
38
39 def __add__(self,other):
40 return self.arg + other
41
42 def __radd__(self,other):
43 return other + self.arg
44
45 def __sub__(self,other):
46 return self.arg - other
47
48 def __rsub__(self,other):
49 return other - self.arg
50
51 def __mul__(self,other):
52 return self.arg * other
53
54 def __rmul__(self,other):
55 return other * self.arg
56
57 def __div__(self,other):
58 return self.arg / other
59
60 def __rdiv__(self,other):
61 return other / self.arg
62
Georg Brandl686eaeb2006-03-28 10:00:53 +000063 def __truediv__(self,other):
64 return self.arg / other
65
66 def __rtruediv__(self,other):
67 return other / self.arg
68
69 def __floordiv__(self,other):
70 return self.arg // other
71
72 def __rfloordiv__(self,other):
73 return other // self.arg
74
Neil Schemenauerfd288c72001-01-02 16:30:31 +000075 def __pow__(self,other):
76 return self.arg ** other
77
78 def __rpow__(self,other):
79 return other ** self.arg
80
81 def __mod__(self,other):
82 return self.arg % other
83
84 def __rmod__(self,other):
85 return other % self.arg
86
87 def __cmp__(self, other):
88 return cmp(self.arg, other)
89
90
Georg Brandl686eaeb2006-03-28 10:00:53 +000091candidates = [2, 2L, 4.0, 2+0j, [1], (2,), None,
92 MethodNumber(2), CoerceNumber(2)]
Neil Schemenauerfd288c72001-01-02 16:30:31 +000093
Georg Brandl686eaeb2006-03-28 10:00:53 +000094infix_binops = [ '+', '-', '*', '**', '%', '//', '/' ]
95
96TE = TypeError
97# b = both normal and augmented give same result list
98# s = single result lists for normal and augmented
99# e = equals other results
100# result lists: ['+', '-', '*', '**', '%', '//', ('classic /', 'new /')]
101# ^^^^^^^^^^^^^^^^^^^^^^
102# 2-tuple if results differ
103# else only one value
104infix_results = {
105 # 2
106 (0,0): ('b', [4, 0, 4, 4, 0, 1, (1, 1.0)]),
107 (0,1): ('e', (0,0)),
108 (0,2): ('b', [6.0, -2.0, 8.0, 16.0, 2.0, 0.0, 0.5]),
109 (0,3): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
110 (0,4): ('b', [TE, TE, [1, 1], TE, TE, TE, TE]),
111 (0,5): ('b', [TE, TE, (2, 2), TE, TE, TE, TE]),
112 (0,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
113 (0,7): ('e', (0,0)),
114 (0,8): ('e', (0,0)),
115
116 # 2L
117 (1,0): ('e', (0,0)),
118 (1,1): ('e', (0,1)),
119 (1,2): ('e', (0,2)),
120 (1,3): ('e', (0,3)),
121 (1,4): ('e', (0,4)),
122 (1,5): ('e', (0,5)),
123 (1,6): ('e', (0,6)),
124 (1,7): ('e', (0,7)),
125 (1,8): ('e', (0,8)),
126
127 # 4.0
128 (2,0): ('b', [6.0, 2.0, 8.0, 16.0, 0.0, 2.0, 2.0]),
129 (2,1): ('e', (2,0)),
130 (2,2): ('b', [8.0, 0.0, 16.0, 256.0, 0.0, 1.0, 1.0]),
131 (2,3): ('b', [6+0j, 2+0j, 8+0j, 16+0j, 0+0j, 2+0j, 2+0j]),
132 (2,4): ('b', [TE, TE, TE, TE, TE, TE, TE]),
133 (2,5): ('e', (2,4)),
134 (2,6): ('e', (2,4)),
135 (2,7): ('e', (2,0)),
136 (2,8): ('e', (2,0)),
137
138 # (2+0j)
139 (3,0): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
140 (3,1): ('e', (3,0)),
141 (3,2): ('b', [6+0j, -2+0j, 8+0j, 16+0j, 2+0j, 0+0j, 0.5+0j]),
142 (3,3): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
143 (3,4): ('b', [TE, TE, TE, TE, TE, TE, TE]),
144 (3,5): ('e', (3,4)),
145 (3,6): ('e', (3,4)),
146 (3,7): ('e', (3,0)),
147 (3,8): ('e', (3,0)),
148
149 # [1]
150 (4,0): ('b', [TE, TE, [1, 1], TE, TE, TE, TE]),
151 (4,1): ('e', (4,0)),
152 (4,2): ('b', [TE, TE, TE, TE, TE, TE, TE]),
153 (4,3): ('b', [TE, TE, TE, TE, TE, TE, TE]),
154 (4,4): ('b', [[1, 1], TE, TE, TE, TE, TE, TE]),
155 (4,5): ('s', [TE, TE, TE, TE, TE, TE, TE], [[1, 2], TE, TE, TE, TE, TE, TE]),
156 (4,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
157 (4,7): ('e', (4,0)),
158 (4,8): ('e', (4,0)),
159
160 # (2,)
161 (5,0): ('b', [TE, TE, (2, 2), TE, TE, TE, TE]),
162 (5,1): ('e', (5,0)),
163 (5,2): ('b', [TE, TE, TE, TE, TE, TE, TE]),
164 (5,3): ('e', (5,2)),
165 (5,4): ('e', (5,2)),
166 (5,5): ('b', [(2, 2), TE, TE, TE, TE, TE, TE]),
167 (5,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
168 (5,7): ('e', (5,0)),
169 (5,8): ('e', (5,0)),
170
171 # None
172 (6,0): ('b', [TE, TE, TE, TE, TE, TE, TE]),
173 (6,1): ('e', (6,0)),
174 (6,2): ('e', (6,0)),
175 (6,3): ('e', (6,0)),
176 (6,4): ('e', (6,0)),
177 (6,5): ('e', (6,0)),
178 (6,6): ('e', (6,0)),
179 (6,7): ('e', (6,0)),
180 (6,8): ('e', (6,0)),
181
182 # MethodNumber(2)
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000183 (7,0): ('e', (0,0)),
Georg Brandl686eaeb2006-03-28 10:00:53 +0000184 (7,1): ('e', (0,1)),
185 (7,2): ('e', (0,2)),
186 (7,3): ('e', (0,3)),
187 (7,4): ('e', (0,4)),
188 (7,5): ('e', (0,5)),
189 (7,6): ('e', (0,6)),
190 (7,7): ('e', (0,7)),
191 (7,8): ('e', (0,8)),
192
193 # CoerceNumber(2)
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000194 (8,0): ('e', (0,0)),
Georg Brandl686eaeb2006-03-28 10:00:53 +0000195 (8,1): ('e', (0,1)),
196 (8,2): ('e', (0,2)),
197 (8,3): ('e', (0,3)),
198 (8,4): ('e', (0,4)),
199 (8,5): ('e', (0,5)),
200 (8,6): ('e', (0,6)),
201 (8,7): ('e', (0,7)),
202 (8,8): ('e', (0,8)),
203}
204
205def process_infix_results():
206 for key in sorted(infix_results):
207 val = infix_results[key]
208 if val[0] == 'e':
209 infix_results[key] = infix_results[val[1]]
210 else:
211 if val[0] == 's':
212 res = (val[1], val[2])
213 elif val[0] == 'b':
214 res = (val[1], val[1])
215 for i in range(1):
216 if isinstance(res[i][6], tuple):
217 if 1/2 == 0:
218 # testing with classic (floor) division
219 res[i][6] = res[i][6][0]
220 else:
221 # testing with -Qnew
222 res[i][6] = res[i][6][1]
223 infix_results[key] = res
224
Anthony Baxter4ef3a232006-03-30 12:59:11 +0000225
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000226with warnings.catch_warnings():
227 # Silence Py3k warning
228 warnings.filterwarnings("ignore", "classic int division",
229 DeprecationWarning)
230 process_infix_results()
Georg Brandl686eaeb2006-03-28 10:00:53 +0000231# now infix_results has two lists of results for every pairing.
232
Neil Schemenauerfd288c72001-01-02 16:30:31 +0000233prefix_binops = [ 'divmod' ]
Georg Brandl686eaeb2006-03-28 10:00:53 +0000234prefix_results = [
235 [(1,0), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1,0)],
236 [(1L,0L), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1L,0L)],
237 [(2.0,0.0), (2.0,0.0), (1.0,0.0), ((2+0j),0j), TE, TE, TE, TE, (2.0,0.0)],
238 [((1+0j),0j), ((1+0j),0j), (0j,(2+0j)), ((1+0j),0j), TE, TE, TE, TE, ((1+0j),0j)],
239 [TE, TE, TE, TE, TE, TE, TE, TE, TE],
240 [TE, TE, TE, TE, TE, TE, TE, TE, TE],
241 [TE, TE, TE, TE, TE, TE, TE, TE, TE],
242 [TE, TE, TE, TE, TE, TE, TE, TE, TE],
243 [(1,0), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1,0)]
244]
Neil Schemenauerfd288c72001-01-02 16:30:31 +0000245
Neil Schemenauer6cbba502004-03-10 17:30:03 +0000246def format_float(value):
247 if abs(value) < 0.01:
248 return '0.0'
249 else:
250 return '%.1f' % value
251
252# avoid testing platform fp quirks
253def format_result(value):
254 if isinstance(value, complex):
255 return '(%s + %sj)' % (format_float(value.real),
256 format_float(value.imag))
257 elif isinstance(value, float):
258 return format_float(value)
259 return str(value)
260
Georg Brandl686eaeb2006-03-28 10:00:53 +0000261class CoercionTest(unittest.TestCase):
262 def test_infix_binops(self):
263 for ia, a in enumerate(candidates):
264 for ib, b in enumerate(candidates):
265 results = infix_results[(ia, ib)]
266 for op, res, ires in zip(infix_binops, results[0], results[1]):
267 if res is TE:
268 self.assertRaises(TypeError, eval,
269 'a %s b' % op, {'a': a, 'b': b})
270 else:
271 self.assertEquals(format_result(res),
272 format_result(eval('a %s b' % op)),
273 '%s %s %s == %s failed' % (a, op, b, res))
274 try:
275 z = copy.copy(a)
276 except copy.Error:
277 z = a # assume it has no inplace ops
278 if ires is TE:
279 try:
280 exec 'z %s= b' % op
281 except TypeError:
282 pass
283 else:
284 self.fail("TypeError not raised")
285 else:
286 exec('z %s= b' % op)
287 self.assertEquals(ires, z)
Neil Schemenauerfd288c72001-01-02 16:30:31 +0000288
Georg Brandl686eaeb2006-03-28 10:00:53 +0000289 def test_prefix_binops(self):
290 for ia, a in enumerate(candidates):
291 for ib, b in enumerate(candidates):
292 for op in prefix_binops:
293 res = prefix_results[ia][ib]
294 if res is TE:
295 self.assertRaises(TypeError, eval,
296 '%s(a, b)' % op, {'a': a, 'b': b})
297 else:
298 self.assertEquals(format_result(res),
299 format_result(eval('%s(a, b)' % op)),
300 '%s(%s, %s) == %s failed' % (op, a, b, res))
Neil Schemenauerfd288c72001-01-02 16:30:31 +0000301
Georg Brandl686eaeb2006-03-28 10:00:53 +0000302 def test_cmptypes(self):
303 # Built-in tp_compare slots expect their arguments to have the
304 # same type, but a user-defined __coerce__ doesn't have to obey.
305 # SF #980352
306 evil_coercer = CoerceTo(42)
307 # Make sure these don't crash any more
308 self.assertNotEquals(cmp(u'fish', evil_coercer), 0)
309 self.assertNotEquals(cmp(slice(1), evil_coercer), 0)
310 # ...but that this still works
311 class WackyComparer(object):
312 def __cmp__(slf, other):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000313 self.assertTrue(other == 42, 'expected evil_coercer, got %r' % other)
Georg Brandl686eaeb2006-03-28 10:00:53 +0000314 return 0
Nick Coghlan48361f52008-08-11 15:45:58 +0000315 __hash__ = None # Invalid cmp makes this unhashable
Georg Brandl686eaeb2006-03-28 10:00:53 +0000316 self.assertEquals(cmp(WackyComparer(), evil_coercer), 0)
317 # ...and classic classes too, since that code path is a little different
318 class ClassicWackyComparer:
319 def __cmp__(slf, other):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000320 self.assertTrue(other == 42, 'expected evil_coercer, got %r' % other)
Georg Brandl686eaeb2006-03-28 10:00:53 +0000321 return 0
322 self.assertEquals(cmp(ClassicWackyComparer(), evil_coercer), 0)
Armin Rigoa1748132004-12-23 22:13:13 +0000323
Brett Cannon5dc3e3f2006-06-13 22:26:13 +0000324 def test_infinite_rec_classic_classes(self):
325 # if __coerce__() returns its arguments reversed it causes an infinite
326 # recursion for classic classes.
327 class Tester:
328 def __coerce__(self, other):
329 return other, self
330
331 exc = TestFailed("__coerce__() returning its arguments reverse "
332 "should raise RuntimeError")
333 try:
334 Tester() + 1
335 except (RuntimeError, TypeError):
336 return
337 except:
338 raise exc
339 else:
340 raise exc
341
Georg Brandl686eaeb2006-03-28 10:00:53 +0000342def test_main():
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000343 with warnings.catch_warnings():
344 # Silence Py3k warnings
345 warnings.filterwarnings("ignore",
346 "complex divmod.., // and % are deprecated",
347 DeprecationWarning)
348 warnings.filterwarnings("ignore", "classic .+ division",
349 DeprecationWarning)
350 run_unittest(CoercionTest)
Armin Rigoa1748132004-12-23 22:13:13 +0000351
Georg Brandl686eaeb2006-03-28 10:00:53 +0000352if __name__ == "__main__":
353 test_main()