blob: fcd2105e5a9a618cbfea312952f9d34d83242b17 [file] [log] [blame]
Neil Schemenauerfd288c72001-01-02 16:30:31 +00001import copy
2import sys
Tim Petersf022a4d2002-04-15 23:52:04 +00003import warnings
Georg Brandl686eaeb2006-03-28 10:00:53 +00004import unittest
5from test.test_support import run_unittest
Neil Schemenauerfd288c72001-01-02 16:30:31 +00006
7# Fake a number that implements numeric methods through __coerce__
8class CoerceNumber:
9 def __init__(self, arg):
10 self.arg = arg
11
12 def __repr__(self):
13 return '<CoerceNumber %s>' % repr(self.arg)
14
15 def __coerce__(self, other):
16 if isinstance(other, CoerceNumber):
17 return self.arg, other.arg
18 else:
19 return (self.arg, other)
20
Georg Brandl686eaeb2006-03-28 10:00:53 +000021# New-style class version of CoerceNumber
22class CoerceTo(object):
23 def __init__(self, arg):
24 self.arg = arg
25 def __coerce__(self, other):
26 if isinstance(other, CoerceTo):
27 return self.arg, other.arg
28 else:
29 return self.arg, other
30
Neil Schemenauerfd288c72001-01-02 16:30:31 +000031
32# Fake a number that implements numeric ops through methods.
33class MethodNumber:
Neil Schemenauerfd288c72001-01-02 16:30:31 +000034 def __init__(self,arg):
35 self.arg = arg
36
37 def __repr__(self):
38 return '<MethodNumber %s>' % repr(self.arg)
39
40 def __add__(self,other):
41 return self.arg + other
42
43 def __radd__(self,other):
44 return other + self.arg
45
46 def __sub__(self,other):
47 return self.arg - other
48
49 def __rsub__(self,other):
50 return other - self.arg
51
52 def __mul__(self,other):
53 return self.arg * other
54
55 def __rmul__(self,other):
56 return other * self.arg
57
58 def __div__(self,other):
59 return self.arg / other
60
61 def __rdiv__(self,other):
62 return other / self.arg
63
Georg Brandl686eaeb2006-03-28 10:00:53 +000064 def __truediv__(self,other):
65 return self.arg / other
66
67 def __rtruediv__(self,other):
68 return other / self.arg
69
70 def __floordiv__(self,other):
71 return self.arg // other
72
73 def __rfloordiv__(self,other):
74 return other // self.arg
75
Neil Schemenauerfd288c72001-01-02 16:30:31 +000076 def __pow__(self,other):
77 return self.arg ** other
78
79 def __rpow__(self,other):
80 return other ** self.arg
81
82 def __mod__(self,other):
83 return self.arg % other
84
85 def __rmod__(self,other):
86 return other % self.arg
87
88 def __cmp__(self, other):
89 return cmp(self.arg, other)
90
91
Georg Brandl686eaeb2006-03-28 10:00:53 +000092candidates = [2, 2L, 4.0, 2+0j, [1], (2,), None,
93 MethodNumber(2), CoerceNumber(2)]
Neil Schemenauerfd288c72001-01-02 16:30:31 +000094
Georg Brandl686eaeb2006-03-28 10:00:53 +000095infix_binops = [ '+', '-', '*', '**', '%', '//', '/' ]
96
97TE = TypeError
98# b = both normal and augmented give same result list
99# s = single result lists for normal and augmented
100# e = equals other results
101# result lists: ['+', '-', '*', '**', '%', '//', ('classic /', 'new /')]
102# ^^^^^^^^^^^^^^^^^^^^^^
103# 2-tuple if results differ
104# else only one value
105infix_results = {
106 # 2
107 (0,0): ('b', [4, 0, 4, 4, 0, 1, (1, 1.0)]),
108 (0,1): ('e', (0,0)),
109 (0,2): ('b', [6.0, -2.0, 8.0, 16.0, 2.0, 0.0, 0.5]),
110 (0,3): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
111 (0,4): ('b', [TE, TE, [1, 1], TE, TE, TE, TE]),
112 (0,5): ('b', [TE, TE, (2, 2), TE, TE, TE, TE]),
113 (0,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
114 (0,7): ('e', (0,0)),
115 (0,8): ('e', (0,0)),
116
117 # 2L
118 (1,0): ('e', (0,0)),
119 (1,1): ('e', (0,1)),
120 (1,2): ('e', (0,2)),
121 (1,3): ('e', (0,3)),
122 (1,4): ('e', (0,4)),
123 (1,5): ('e', (0,5)),
124 (1,6): ('e', (0,6)),
125 (1,7): ('e', (0,7)),
126 (1,8): ('e', (0,8)),
127
128 # 4.0
129 (2,0): ('b', [6.0, 2.0, 8.0, 16.0, 0.0, 2.0, 2.0]),
130 (2,1): ('e', (2,0)),
131 (2,2): ('b', [8.0, 0.0, 16.0, 256.0, 0.0, 1.0, 1.0]),
132 (2,3): ('b', [6+0j, 2+0j, 8+0j, 16+0j, 0+0j, 2+0j, 2+0j]),
133 (2,4): ('b', [TE, TE, TE, TE, TE, TE, TE]),
134 (2,5): ('e', (2,4)),
135 (2,6): ('e', (2,4)),
136 (2,7): ('e', (2,0)),
137 (2,8): ('e', (2,0)),
138
139 # (2+0j)
140 (3,0): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
141 (3,1): ('e', (3,0)),
142 (3,2): ('b', [6+0j, -2+0j, 8+0j, 16+0j, 2+0j, 0+0j, 0.5+0j]),
143 (3,3): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
144 (3,4): ('b', [TE, TE, TE, TE, TE, TE, TE]),
145 (3,5): ('e', (3,4)),
146 (3,6): ('e', (3,4)),
147 (3,7): ('e', (3,0)),
148 (3,8): ('e', (3,0)),
149
150 # [1]
151 (4,0): ('b', [TE, TE, [1, 1], TE, TE, TE, TE]),
152 (4,1): ('e', (4,0)),
153 (4,2): ('b', [TE, TE, TE, TE, TE, TE, TE]),
154 (4,3): ('b', [TE, TE, TE, TE, TE, TE, TE]),
155 (4,4): ('b', [[1, 1], TE, TE, TE, TE, TE, TE]),
156 (4,5): ('s', [TE, TE, TE, TE, TE, TE, TE], [[1, 2], TE, TE, TE, TE, TE, TE]),
157 (4,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
158 (4,7): ('e', (4,0)),
159 (4,8): ('e', (4,0)),
160
161 # (2,)
162 (5,0): ('b', [TE, TE, (2, 2), TE, TE, TE, TE]),
163 (5,1): ('e', (5,0)),
164 (5,2): ('b', [TE, TE, TE, TE, TE, TE, TE]),
165 (5,3): ('e', (5,2)),
166 (5,4): ('e', (5,2)),
167 (5,5): ('b', [(2, 2), TE, TE, TE, TE, TE, TE]),
168 (5,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
169 (5,7): ('e', (5,0)),
170 (5,8): ('e', (5,0)),
171
172 # None
173 (6,0): ('b', [TE, TE, TE, TE, TE, TE, TE]),
174 (6,1): ('e', (6,0)),
175 (6,2): ('e', (6,0)),
176 (6,3): ('e', (6,0)),
177 (6,4): ('e', (6,0)),
178 (6,5): ('e', (6,0)),
179 (6,6): ('e', (6,0)),
180 (6,7): ('e', (6,0)),
181 (6,8): ('e', (6,0)),
182
183 # MethodNumber(2)
184 (7,0): ('e', (0,0)),
185 (7,1): ('e', (0,1)),
186 (7,2): ('e', (0,2)),
187 (7,3): ('e', (0,3)),
188 (7,4): ('e', (0,4)),
189 (7,5): ('e', (0,5)),
190 (7,6): ('e', (0,6)),
191 (7,7): ('e', (0,7)),
192 (7,8): ('e', (0,8)),
193
194 # CoerceNumber(2)
195 (8,0): ('e', (0,0)),
196 (8,1): ('e', (0,1)),
197 (8,2): ('e', (0,2)),
198 (8,3): ('e', (0,3)),
199 (8,4): ('e', (0,4)),
200 (8,5): ('e', (0,5)),
201 (8,6): ('e', (0,6)),
202 (8,7): ('e', (0,7)),
203 (8,8): ('e', (0,8)),
204}
205
206def process_infix_results():
207 for key in sorted(infix_results):
208 val = infix_results[key]
209 if val[0] == 'e':
210 infix_results[key] = infix_results[val[1]]
211 else:
212 if val[0] == 's':
213 res = (val[1], val[2])
214 elif val[0] == 'b':
215 res = (val[1], val[1])
216 for i in range(1):
217 if isinstance(res[i][6], tuple):
218 if 1/2 == 0:
219 # testing with classic (floor) division
220 res[i][6] = res[i][6][0]
221 else:
222 # testing with -Qnew
223 res[i][6] = res[i][6][1]
224 infix_results[key] = res
225
226
227
228process_infix_results()
229# now infix_results has two lists of results for every pairing.
230
Neil Schemenauerfd288c72001-01-02 16:30:31 +0000231prefix_binops = [ 'divmod' ]
Georg Brandl686eaeb2006-03-28 10:00:53 +0000232prefix_results = [
233 [(1,0), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1,0)],
234 [(1L,0L), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1L,0L)],
235 [(2.0,0.0), (2.0,0.0), (1.0,0.0), ((2+0j),0j), TE, TE, TE, TE, (2.0,0.0)],
236 [((1+0j),0j), ((1+0j),0j), (0j,(2+0j)), ((1+0j),0j), TE, TE, TE, TE, ((1+0j),0j)],
237 [TE, TE, TE, TE, TE, TE, TE, TE, TE],
238 [TE, TE, TE, TE, TE, TE, TE, TE, TE],
239 [TE, TE, TE, TE, TE, TE, TE, TE, TE],
240 [TE, TE, TE, TE, TE, TE, TE, TE, TE],
241 [(1,0), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1,0)]
242]
Neil Schemenauerfd288c72001-01-02 16:30:31 +0000243
Neil Schemenauer6cbba502004-03-10 17:30:03 +0000244def format_float(value):
245 if abs(value) < 0.01:
246 return '0.0'
247 else:
248 return '%.1f' % value
249
250# avoid testing platform fp quirks
251def format_result(value):
252 if isinstance(value, complex):
253 return '(%s + %sj)' % (format_float(value.real),
254 format_float(value.imag))
255 elif isinstance(value, float):
256 return format_float(value)
257 return str(value)
258
Georg Brandl686eaeb2006-03-28 10:00:53 +0000259class CoercionTest(unittest.TestCase):
260 def test_infix_binops(self):
261 for ia, a in enumerate(candidates):
262 for ib, b in enumerate(candidates):
263 results = infix_results[(ia, ib)]
264 for op, res, ires in zip(infix_binops, results[0], results[1]):
265 if res is TE:
266 self.assertRaises(TypeError, eval,
267 'a %s b' % op, {'a': a, 'b': b})
268 else:
269 self.assertEquals(format_result(res),
270 format_result(eval('a %s b' % op)),
271 '%s %s %s == %s failed' % (a, op, b, res))
272 try:
273 z = copy.copy(a)
274 except copy.Error:
275 z = a # assume it has no inplace ops
276 if ires is TE:
277 try:
278 exec 'z %s= b' % op
279 except TypeError:
280 pass
281 else:
282 self.fail("TypeError not raised")
283 else:
284 exec('z %s= b' % op)
285 self.assertEquals(ires, z)
Neil Schemenauerfd288c72001-01-02 16:30:31 +0000286
Georg Brandl686eaeb2006-03-28 10:00:53 +0000287 def test_prefix_binops(self):
288 for ia, a in enumerate(candidates):
289 for ib, b in enumerate(candidates):
290 for op in prefix_binops:
291 res = prefix_results[ia][ib]
292 if res is TE:
293 self.assertRaises(TypeError, eval,
294 '%s(a, b)' % op, {'a': a, 'b': b})
295 else:
296 self.assertEquals(format_result(res),
297 format_result(eval('%s(a, b)' % op)),
298 '%s(%s, %s) == %s failed' % (op, a, b, res))
Neil Schemenauerfd288c72001-01-02 16:30:31 +0000299
Georg Brandl686eaeb2006-03-28 10:00:53 +0000300 def test_cmptypes(self):
301 # Built-in tp_compare slots expect their arguments to have the
302 # same type, but a user-defined __coerce__ doesn't have to obey.
303 # SF #980352
304 evil_coercer = CoerceTo(42)
305 # Make sure these don't crash any more
306 self.assertNotEquals(cmp(u'fish', evil_coercer), 0)
307 self.assertNotEquals(cmp(slice(1), evil_coercer), 0)
308 # ...but that this still works
309 class WackyComparer(object):
310 def __cmp__(slf, other):
311 self.assert_(other == 42, 'expected evil_coercer, got %r' % other)
312 return 0
313 self.assertEquals(cmp(WackyComparer(), evil_coercer), 0)
314 # ...and classic classes too, since that code path is a little different
315 class ClassicWackyComparer:
316 def __cmp__(slf, other):
317 self.assert_(other == 42, 'expected evil_coercer, got %r' % other)
318 return 0
319 self.assertEquals(cmp(ClassicWackyComparer(), evil_coercer), 0)
Armin Rigoa1748132004-12-23 22:13:13 +0000320
Georg Brandl686eaeb2006-03-28 10:00:53 +0000321def test_main():
322 warnings.filterwarnings("ignore",
323 r'complex divmod\(\), // and % are deprecated',
324 DeprecationWarning,
325 r'test.test_coercion$')
326 run_unittest(CoercionTest)
Armin Rigoa1748132004-12-23 22:13:13 +0000327
Georg Brandl686eaeb2006-03-28 10:00:53 +0000328if __name__ == "__main__":
329 test_main()