blob: bde63a8045f42038716b38c6eb97666e2649bd64 [file] [log] [blame]
Thomas Wouters1d75a792000-08-17 22:37:32 +00001"Test the functionality of Python classes implementing operators."
2
Thomas Woutersed03b412007-08-28 21:37:11 +00003import unittest
4import sys
5
6from test import test_support
Thomas Wouters1d75a792000-08-17 22:37:32 +00007
8testmeths = [
9
10# Binary operations
11 "add",
12 "radd",
13 "sub",
14 "rsub",
15 "mul",
16 "rmul",
Neal Norwitzbcc0db82006-03-24 08:14:36 +000017 "truediv",
18 "rtruediv",
Thomas Wouters1d75a792000-08-17 22:37:32 +000019 "mod",
20 "rmod",
21 "divmod",
22 "rdivmod",
23 "pow",
24 "rpow",
25 "rshift",
26 "rrshift",
27 "lshift",
28 "rlshift",
29 "and",
30 "rand",
31 "or",
32 "ror",
33 "xor",
34 "rxor",
35
36# List/dict operations
37 "contains",
38 "getitem",
39 "getslice",
40 "setitem",
41 "setslice",
42 "delitem",
43 "delslice",
44
45# Unary operations
46 "neg",
47 "pos",
48 "abs",
Thomas Wouters1d75a792000-08-17 22:37:32 +000049
50# generic operations
51 "init",
Thomas Wouters1d75a792000-08-17 22:37:32 +000052 ]
53
54# These need to return something other than None
Thomas Wouters1d75a792000-08-17 22:37:32 +000055# "hash",
56# "str",
57# "repr",
Neil Schemenauer3a313e32004-07-19 16:29:17 +000058# "int",
Neil Schemenauer3a313e32004-07-19 16:29:17 +000059# "float",
Thomas Wouters1d75a792000-08-17 22:37:32 +000060
61# These are separate because they can influence the test of other methods.
62# "getattr",
63# "setattr",
64# "delattr",
65
Thomas Woutersed03b412007-08-28 21:37:11 +000066callLst = []
67def trackCall(f):
68 def track(*args, **kwargs):
69 callLst.append((f.__name__, args))
70 return f(*args, **kwargs)
71 return track
Thomas Wouters1d75a792000-08-17 22:37:32 +000072
Thomas Woutersed03b412007-08-28 21:37:11 +000073statictests = """
74@trackCall
75def __hash__(self, *args):
76 return hash(id(self))
Thomas Wouters1d75a792000-08-17 22:37:32 +000077
Thomas Woutersed03b412007-08-28 21:37:11 +000078@trackCall
79def __str__(self, *args):
80 return "AllTests"
Thomas Wouters1d75a792000-08-17 22:37:32 +000081
Thomas Woutersed03b412007-08-28 21:37:11 +000082@trackCall
83def __repr__(self, *args):
84 return "AllTests"
Neil Schemenauer3a313e32004-07-19 16:29:17 +000085
Thomas Woutersed03b412007-08-28 21:37:11 +000086@trackCall
87def __int__(self, *args):
88 return 1
Guido van Rossumcd16bf62007-06-13 18:07:49 +000089
Thomas Woutersed03b412007-08-28 21:37:11 +000090@trackCall
91def __index__(self, *args):
92 return 1
Neil Schemenauer3a313e32004-07-19 16:29:17 +000093
Thomas Woutersed03b412007-08-28 21:37:11 +000094@trackCall
95def __float__(self, *args):
96 return 1.0
Thomas Wouters1d75a792000-08-17 22:37:32 +000097
Thomas Woutersed03b412007-08-28 21:37:11 +000098@trackCall
99def __cmp__(self, *args):
100 return 0
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000101
Thomas Woutersed03b412007-08-28 21:37:11 +0000102@trackCall
103def __eq__(self, *args):
104 return True
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000105
Thomas Woutersed03b412007-08-28 21:37:11 +0000106@trackCall
107def __ne__(self, *args):
108 return False
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000109
Thomas Woutersed03b412007-08-28 21:37:11 +0000110@trackCall
111def __lt__(self, *args):
112 return False
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000113
Thomas Woutersed03b412007-08-28 21:37:11 +0000114@trackCall
115def __le__(self, *args):
116 return True
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000117
Thomas Woutersed03b412007-08-28 21:37:11 +0000118@trackCall
119def __gt__(self, *args):
120 return False
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000121
Thomas Woutersed03b412007-08-28 21:37:11 +0000122@trackCall
123def __ge__(self, *args):
124 return True
125"""
Barry Warsaw07d8d642001-08-20 20:29:07 +0000126
Thomas Woutersed03b412007-08-28 21:37:11 +0000127# Synthesize all the other AllTests methods from the names in testmeths.
Tim Peters01705212001-12-11 19:28:47 +0000128
129method_template = """\
Thomas Woutersed03b412007-08-28 21:37:11 +0000130@trackCall
131def __%s__(self, *args):
132 pass
Tim Peters01705212001-12-11 19:28:47 +0000133"""
134
Thomas Wouters4cdada92006-04-15 09:19:16 +0000135d = {}
Thomas Woutersed03b412007-08-28 21:37:11 +0000136exec(statictests, globals(), d)
Thomas Wouters1d75a792000-08-17 22:37:32 +0000137for method in testmeths:
Thomas Woutersed03b412007-08-28 21:37:11 +0000138 exec(method_template % method, globals(), d)
139AllTests = type("AllTests", (object,), d)
140del d, statictests, method, method_template
Thomas Wouters1d75a792000-08-17 22:37:32 +0000141
Thomas Woutersed03b412007-08-28 21:37:11 +0000142class ClassTests(unittest.TestCase):
143 def setUp(self):
144 callLst[:] = []
Thomas Wouters1d75a792000-08-17 22:37:32 +0000145
Thomas Woutersed03b412007-08-28 21:37:11 +0000146 def assertCallStack(self, expected_calls):
147 actualCallList = callLst[:] # need to copy because the comparison below will add
148 # additional calls to callLst
149 if expected_calls != actualCallList:
150 self.fail("Expected call list:\n %s\ndoes not match actual call list\n %s" %
151 (expected_calls, actualCallList))
Thomas Wouters1d75a792000-08-17 22:37:32 +0000152
Thomas Woutersed03b412007-08-28 21:37:11 +0000153 def testInit(self):
154 foo = AllTests()
155 self.assertCallStack([("__init__", (foo,))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000156
Thomas Woutersed03b412007-08-28 21:37:11 +0000157 def testBinaryOps(self):
158 testme = AllTests()
159 # Binary operations
Thomas Wouters1d75a792000-08-17 22:37:32 +0000160
Thomas Woutersed03b412007-08-28 21:37:11 +0000161 callLst[:] = []
162 testme + 1
163 self.assertCallStack([("__add__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000164
Thomas Woutersed03b412007-08-28 21:37:11 +0000165 callLst[:] = []
166 1 + testme
167 self.assertCallStack([("__radd__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000168
Thomas Woutersed03b412007-08-28 21:37:11 +0000169 callLst[:] = []
170 testme - 1
171 self.assertCallStack([("__sub__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000172
Thomas Woutersed03b412007-08-28 21:37:11 +0000173 callLst[:] = []
174 1 - testme
175 self.assertCallStack([("__rsub__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000176
Thomas Woutersed03b412007-08-28 21:37:11 +0000177 callLst[:] = []
178 testme * 1
179 self.assertCallStack([("__mul__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000180
Thomas Woutersed03b412007-08-28 21:37:11 +0000181 callLst[:] = []
182 1 * testme
183 self.assertCallStack([("__rmul__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000184
Thomas Woutersed03b412007-08-28 21:37:11 +0000185 if 1/2 == 0:
186 callLst[:] = []
187 testme / 1
188 self.assertCallStack([("__div__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000189
190
Thomas Woutersed03b412007-08-28 21:37:11 +0000191 callLst[:] = []
192 1 / testme
193 self.assertCallStack([("__rdiv__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000194
Thomas Woutersed03b412007-08-28 21:37:11 +0000195 callLst[:] = []
196 testme % 1
197 self.assertCallStack([("__mod__", (testme, 1))])
Thomas Wouters89f507f2006-12-13 04:49:30 +0000198
Thomas Woutersed03b412007-08-28 21:37:11 +0000199 callLst[:] = []
200 1 % testme
201 self.assertCallStack([("__rmod__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000202
203
Thomas Woutersed03b412007-08-28 21:37:11 +0000204 callLst[:] = []
205 divmod(testme,1)
206 self.assertCallStack([("__divmod__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000207
Thomas Woutersed03b412007-08-28 21:37:11 +0000208 callLst[:] = []
209 divmod(1, testme)
210 self.assertCallStack([("__rdivmod__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000211
Thomas Woutersed03b412007-08-28 21:37:11 +0000212 callLst[:] = []
213 testme ** 1
214 self.assertCallStack([("__pow__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000215
Thomas Woutersed03b412007-08-28 21:37:11 +0000216 callLst[:] = []
217 1 ** testme
218 self.assertCallStack([("__rpow__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000219
Thomas Woutersed03b412007-08-28 21:37:11 +0000220 callLst[:] = []
221 testme >> 1
222 self.assertCallStack([("__rshift__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000223
Thomas Woutersed03b412007-08-28 21:37:11 +0000224 callLst[:] = []
225 1 >> testme
226 self.assertCallStack([("__rrshift__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000227
Thomas Woutersed03b412007-08-28 21:37:11 +0000228 callLst[:] = []
229 testme << 1
230 self.assertCallStack([("__lshift__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000231
Thomas Woutersed03b412007-08-28 21:37:11 +0000232 callLst[:] = []
233 1 << testme
234 self.assertCallStack([("__rlshift__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000235
Thomas Woutersed03b412007-08-28 21:37:11 +0000236 callLst[:] = []
237 testme & 1
238 self.assertCallStack([("__and__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000239
Thomas Woutersed03b412007-08-28 21:37:11 +0000240 callLst[:] = []
241 1 & testme
242 self.assertCallStack([("__rand__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000243
Thomas Woutersed03b412007-08-28 21:37:11 +0000244 callLst[:] = []
245 testme | 1
246 self.assertCallStack([("__or__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000247
Thomas Woutersed03b412007-08-28 21:37:11 +0000248 callLst[:] = []
249 1 | testme
250 self.assertCallStack([("__ror__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000251
Thomas Woutersed03b412007-08-28 21:37:11 +0000252 callLst[:] = []
253 testme ^ 1
254 self.assertCallStack([("__xor__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000255
Thomas Woutersed03b412007-08-28 21:37:11 +0000256 callLst[:] = []
257 1 ^ testme
258 self.assertCallStack([("__rxor__", (testme, 1))])
Thomas Wouters1d75a792000-08-17 22:37:32 +0000259
Thomas Woutersed03b412007-08-28 21:37:11 +0000260 def testListAndDictOps(self):
261 testme = AllTests()
262
263 # List/dict operations
264
265 class Empty: pass
266
267 try:
268 1 in Empty()
269 self.fail('failed, should have raised TypeError')
270 except TypeError:
271 pass
272
273 callLst[:] = []
274 1 in testme
275 self.assertCallStack([('__contains__', (testme, 1))])
276
277 callLst[:] = []
278 testme[1]
279 self.assertCallStack([('__getitem__', (testme, 1))])
280
281 callLst[:] = []
282 testme[1] = 1
283 self.assertCallStack([('__setitem__', (testme, 1, 1))])
284
285 callLst[:] = []
286 del testme[1]
287 self.assertCallStack([('__delitem__', (testme, 1))])
288
289 callLst[:] = []
290 testme[:42]
291 self.assertCallStack([('__getslice__', (testme, 0, 42))])
292
293 callLst[:] = []
294 testme[:42] = "The Answer"
295 self.assertCallStack([('__setslice__', (testme, 0, 42, "The Answer"))])
296
297 callLst[:] = []
298 del testme[:42]
299 self.assertCallStack([('__delslice__', (testme, 0, 42))])
300
301 callLst[:] = []
302 testme[2:1024:10]
303 self.assertCallStack([('__getitem__', (testme, slice(2, 1024, 10)))])
304
305 callLst[:] = []
306 testme[2:1024:10] = "A lot"
307 self.assertCallStack([('__setitem__', (testme, slice(2, 1024, 10),
308 "A lot"))])
309 callLst[:] = []
310 del testme[2:1024:10]
311 self.assertCallStack([('__delitem__', (testme, slice(2, 1024, 10)))])
312
313 callLst[:] = []
314 testme[:42, ..., :24:, 24, 100]
315 self.assertCallStack([('__getitem__', (testme, (slice(None, 42, None),
316 Ellipsis,
317 slice(None, 24, None),
318 24, 100)))])
319 callLst[:] = []
320 testme[:42, ..., :24:, 24, 100] = "Strange"
321 self.assertCallStack([('__setitem__', (testme, (slice(None, 42, None),
322 Ellipsis,
323 slice(None, 24, None),
324 24, 100), "Strange"))])
325 callLst[:] = []
326 del testme[:42, ..., :24:, 24, 100]
327 self.assertCallStack([('__delitem__', (testme, (slice(None, 42, None),
328 Ellipsis,
329 slice(None, 24, None),
330 24, 100)))])
331
332 # Now remove the slice hooks to see if converting normal slices to
333 # slice object works.
334
335 getslice = AllTests.__getslice__
336 del AllTests.__getslice__
337 setslice = AllTests.__setslice__
338 del AllTests.__setslice__
339 delslice = AllTests.__delslice__
340 del AllTests.__delslice__
341
342 # XXX when using new-style classes the slice testme[:42] produces
343 # slice(None, 42, None) instead of slice(0, 42, None). py3k will have
344 # to change this test.
345 callLst[:] = []
346 testme[0:42]
347 self.assertCallStack([('__getitem__', (testme, slice(0, 42, None)))])
348
349 callLst[:] = []
350 testme[:42] = "The Answer"
351 self.assertCallStack([('__setitem__', (testme, slice(None, 42, None),
352 "The Answer"))])
353 callLst[:] = []
354 del testme[0:42]
355 self.assertCallStack([('__delitem__', (testme, slice(0, 42, None)))])
356
357 # Restore the slice methods, or the tests will fail with regrtest -R.
358 AllTests.__getslice__ = getslice
359 AllTests.__setslice__ = setslice
360 AllTests.__delslice__ = delslice
Guido van Rossum23120242001-01-18 23:47:15 +0000361
362
Thomas Woutersed03b412007-08-28 21:37:11 +0000363 def testUnaryOps(self):
364 testme = AllTests()
Neil Schemenauer3a313e32004-07-19 16:29:17 +0000365
Thomas Woutersed03b412007-08-28 21:37:11 +0000366 callLst[:] = []
367 -testme
368 self.assertCallStack([('__neg__', (testme,))])
369 callLst[:] = []
370 +testme
371 self.assertCallStack([('__pos__', (testme,))])
372 callLst[:] = []
373 abs(testme)
374 self.assertCallStack([('__abs__', (testme,))])
375 callLst[:] = []
376 int(testme)
377 self.assertCallStack([('__int__', (testme,))])
378 callLst[:] = []
379 float(testme)
380 self.assertCallStack([('__float__', (testme,))])
381 callLst[:] = []
382 oct(testme)
383 self.assertCallStack([('__index__', (testme,))])
384 callLst[:] = []
385 hex(testme)
386 self.assertCallStack([('__index__', (testme,))])
Guido van Rossum2c9590f2002-10-29 19:08:29 +0000387
388
Thomas Woutersed03b412007-08-28 21:37:11 +0000389 def testMisc(self):
390 testme = AllTests()
Guido van Rossum2c9590f2002-10-29 19:08:29 +0000391
Thomas Woutersed03b412007-08-28 21:37:11 +0000392 callLst[:] = []
393 hash(testme)
394 self.assertCallStack([('__hash__', (testme,))])
Guido van Rossum2c9590f2002-10-29 19:08:29 +0000395
Thomas Woutersed03b412007-08-28 21:37:11 +0000396 callLst[:] = []
397 repr(testme)
398 self.assertCallStack([('__repr__', (testme,))])
Guido van Rossum2c9590f2002-10-29 19:08:29 +0000399
Thomas Woutersed03b412007-08-28 21:37:11 +0000400 callLst[:] = []
401 str(testme)
402 self.assertCallStack([('__str__', (testme,))])
Guido van Rossum2c9590f2002-10-29 19:08:29 +0000403
Thomas Woutersed03b412007-08-28 21:37:11 +0000404 callLst[:] = []
405 testme == 1
406 self.assertCallStack([('__eq__', (testme, 1))])
407
408 callLst[:] = []
409 testme < 1
410 self.assertCallStack([('__lt__', (testme, 1))])
411
412 callLst[:] = []
413 testme > 1
414 self.assertCallStack([('__gt__', (testme, 1))])
415
416 callLst[:] = []
417 testme != 1
418 self.assertCallStack([('__ne__', (testme, 1))])
419
420 callLst[:] = []
421 1 == testme
422 self.assertCallStack([('__eq__', (1, testme))])
423
424 callLst[:] = []
425 1 < testme
426 self.assertCallStack([('__gt__', (1, testme))])
427
428 callLst[:] = []
429 1 > testme
430 self.assertCallStack([('__lt__', (1, testme))])
431
432 callLst[:] = []
433 1 != testme
434 self.assertCallStack([('__ne__', (1, testme))])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000435
436
Thomas Woutersed03b412007-08-28 21:37:11 +0000437 def testGetSetAndDel(self):
438 # Interfering tests
439 class ExtraTests(AllTests):
440 @trackCall
441 def __getattr__(self, *args):
442 return "SomeVal"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000443
Thomas Woutersed03b412007-08-28 21:37:11 +0000444 @trackCall
445 def __setattr__(self, *args):
446 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000447
Thomas Woutersed03b412007-08-28 21:37:11 +0000448 @trackCall
449 def __delattr__(self, *args):
450 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000451
Thomas Woutersed03b412007-08-28 21:37:11 +0000452 testme = ExtraTests()
453
454 callLst[:] = []
455 testme.spam
456 self.assertCallStack([('__getattr__', (testme, "spam"))])
457
458 callLst[:] = []
459 testme.eggs = "spam, spam, spam and ham"
460 self.assertCallStack([('__setattr__', (testme, "eggs",
461 "spam, spam, spam and ham"))])
462
463 callLst[:] = []
464 del testme.cardinal
465 self.assertCallStack([('__delattr__', (testme, "cardinal"))])
466
467 def testDel(self):
468 x = []
469
470 class DelTest:
471 def __del__(self):
472 x.append("crab people, crab people")
473 testme = DelTest()
474 del testme
475 import gc
476 gc.collect()
477 self.assertEquals(["crab people, crab people"], x)
478
479 def testBadTypeReturned(self):
480 # return values of some method are type-checked
481 class BadTypeClass:
482 def __int__(self):
483 return None
484 __float__ = __int__
485 __str__ = __int__
486 __repr__ = __int__
487 __oct__ = __int__
488 __hex__ = __int__
489
490 for f in [int, float, str, repr, oct, hex]:
491 self.assertRaises(TypeError, f, BadTypeClass())
492
493 def testHashStuff(self):
494 # Test correct errors from hash() on objects with comparisons but
495 # no __hash__
496
497 class C0:
498 pass
499
500 hash(C0()) # This should work; the next two should raise TypeError
501
502 class C1:
503 def __cmp__(self, other): return 0
504
505 self.assertRaises(TypeError, hash, C1())
506
507 class C2:
508 def __eq__(self, other): return 1
509
510 self.assertRaises(TypeError, hash, C2())
511
512
513 def testSFBug532646(self):
514 # Test for SF bug 532646
515
516 class A:
517 pass
518 A.__call__ = A()
519 a = A()
520
521 try:
522 a() # This should not segfault
523 except RuntimeError:
524 pass
525 else:
526 self.fail("Failed to raise RuntimeError")
527
528 def testForExceptionsRaisedInInstanceGetattr2(self):
529 # Tests for exceptions raised in instance_getattr2().
530
531 def booh(self):
532 raise AttributeError("booh")
533
534 class A:
535 a = property(booh)
536 try:
537 A().a # Raised AttributeError: A instance has no attribute 'a'
538 except AttributeError as x:
539 if str(x) != "booh":
540 self.fail("attribute error for A().a got masked: %s" % x)
541
542 class E:
543 __eq__ = property(booh)
544 E() == E() # In debug mode, caused a C-level assert() to fail
545
546 class I:
547 __init__ = property(booh)
548 try:
549 # In debug mode, printed XXX undetected error and
550 # raises AttributeError
551 I()
552 except AttributeError as x:
553 pass
554 else:
555 self.fail("attribute error for I.__init__ got masked")
556
557 def testHashComparisonOfMethods(self):
558 # Test comparison and hash of methods
559 class A:
560 def __init__(self, x):
561 self.x = x
562 def f(self):
563 pass
564 def g(self):
565 pass
566 def __eq__(self, other):
567 return self.x == other.x
568 def __hash__(self):
569 return self.x
570 class B(A):
571 pass
572
573 a1 = A(1)
574 a2 = A(2)
575 self.assertEquals(a1.f, a1.f)
576 self.assertNotEquals(a1.f, a2.f)
577 self.assertNotEquals(a1.f, a1.g)
578 self.assertEquals(a1.f, A(1).f)
579 self.assertEquals(hash(a1.f), hash(a1.f))
580 self.assertEquals(hash(a1.f), hash(A(1).f))
581
582 self.assertNotEquals(A.f, a1.f)
583 self.assertNotEquals(A.f, A.g)
584 self.assertEquals(B.f, A.f)
585 self.assertEquals(hash(B.f), hash(A.f))
586
587 # the following triggers a SystemError in 2.4
588 a = A(hash(A.f.im_func)^(-1))
589 hash(a.f)
590
591def test_main():
592 test_support.run_unittest(ClassTests)
593
594if __name__=='__main__':
595 test_main()