make file closing more robust
[python/dscho.git] / Lib / test / test_class.py
blob552c521cdfa2905c46ef1ee9868600f1ca389b9c
1 "Test the functionality of Python classes implementing operators."
3 import unittest
5 from test import support
7 testmeths = [
9 # Binary operations
10 "add",
11 "radd",
12 "sub",
13 "rsub",
14 "mul",
15 "rmul",
16 "truediv",
17 "rtruediv",
18 "mod",
19 "rmod",
20 "divmod",
21 "rdivmod",
22 "pow",
23 "rpow",
24 "rshift",
25 "rrshift",
26 "lshift",
27 "rlshift",
28 "and",
29 "rand",
30 "or",
31 "ror",
32 "xor",
33 "rxor",
35 # List/dict operations
36 "contains",
37 "getitem",
38 "setitem",
39 "delitem",
41 # Unary operations
42 "neg",
43 "pos",
44 "abs",
46 # generic operations
47 "init",
50 # These need to return something other than None
51 # "hash",
52 # "str",
53 # "repr",
54 # "int",
55 # "float",
57 # These are separate because they can influence the test of other methods.
58 # "getattr",
59 # "setattr",
60 # "delattr",
62 callLst = []
63 def trackCall(f):
64 def track(*args, **kwargs):
65 callLst.append((f.__name__, args))
66 return f(*args, **kwargs)
67 return track
69 statictests = """
70 @trackCall
71 def __hash__(self, *args):
72 return hash(id(self))
74 @trackCall
75 def __str__(self, *args):
76 return "AllTests"
78 @trackCall
79 def __repr__(self, *args):
80 return "AllTests"
82 @trackCall
83 def __int__(self, *args):
84 return 1
86 @trackCall
87 def __index__(self, *args):
88 return 1
90 @trackCall
91 def __float__(self, *args):
92 return 1.0
94 @trackCall
95 def __eq__(self, *args):
96 return True
98 @trackCall
99 def __ne__(self, *args):
100 return False
102 @trackCall
103 def __lt__(self, *args):
104 return False
106 @trackCall
107 def __le__(self, *args):
108 return True
110 @trackCall
111 def __gt__(self, *args):
112 return False
114 @trackCall
115 def __ge__(self, *args):
116 return True
119 # Synthesize all the other AllTests methods from the names in testmeths.
121 method_template = """\
122 @trackCall
123 def __%s__(self, *args):
124 pass
127 d = {}
128 exec(statictests, globals(), d)
129 for method in testmeths:
130 exec(method_template % method, globals(), d)
131 AllTests = type("AllTests", (object,), d)
132 del d, statictests, method, method_template
134 class ClassTests(unittest.TestCase):
135 def setUp(self):
136 callLst[:] = []
138 def assertCallStack(self, expected_calls):
139 actualCallList = callLst[:] # need to copy because the comparison below will add
140 # additional calls to callLst
141 if expected_calls != actualCallList:
142 self.fail("Expected call list:\n %s\ndoes not match actual call list\n %s" %
143 (expected_calls, actualCallList))
145 def testInit(self):
146 foo = AllTests()
147 self.assertCallStack([("__init__", (foo,))])
149 def testBinaryOps(self):
150 testme = AllTests()
151 # Binary operations
153 callLst[:] = []
154 testme + 1
155 self.assertCallStack([("__add__", (testme, 1))])
157 callLst[:] = []
158 1 + testme
159 self.assertCallStack([("__radd__", (testme, 1))])
161 callLst[:] = []
162 testme - 1
163 self.assertCallStack([("__sub__", (testme, 1))])
165 callLst[:] = []
166 1 - testme
167 self.assertCallStack([("__rsub__", (testme, 1))])
169 callLst[:] = []
170 testme * 1
171 self.assertCallStack([("__mul__", (testme, 1))])
173 callLst[:] = []
174 1 * testme
175 self.assertCallStack([("__rmul__", (testme, 1))])
177 if 1/2 == 0:
178 callLst[:] = []
179 testme / 1
180 self.assertCallStack([("__div__", (testme, 1))])
183 callLst[:] = []
184 1 / testme
185 self.assertCallStack([("__rdiv__", (testme, 1))])
187 callLst[:] = []
188 testme % 1
189 self.assertCallStack([("__mod__", (testme, 1))])
191 callLst[:] = []
192 1 % testme
193 self.assertCallStack([("__rmod__", (testme, 1))])
196 callLst[:] = []
197 divmod(testme,1)
198 self.assertCallStack([("__divmod__", (testme, 1))])
200 callLst[:] = []
201 divmod(1, testme)
202 self.assertCallStack([("__rdivmod__", (testme, 1))])
204 callLst[:] = []
205 testme ** 1
206 self.assertCallStack([("__pow__", (testme, 1))])
208 callLst[:] = []
209 1 ** testme
210 self.assertCallStack([("__rpow__", (testme, 1))])
212 callLst[:] = []
213 testme >> 1
214 self.assertCallStack([("__rshift__", (testme, 1))])
216 callLst[:] = []
217 1 >> testme
218 self.assertCallStack([("__rrshift__", (testme, 1))])
220 callLst[:] = []
221 testme << 1
222 self.assertCallStack([("__lshift__", (testme, 1))])
224 callLst[:] = []
225 1 << testme
226 self.assertCallStack([("__rlshift__", (testme, 1))])
228 callLst[:] = []
229 testme & 1
230 self.assertCallStack([("__and__", (testme, 1))])
232 callLst[:] = []
233 1 & testme
234 self.assertCallStack([("__rand__", (testme, 1))])
236 callLst[:] = []
237 testme | 1
238 self.assertCallStack([("__or__", (testme, 1))])
240 callLst[:] = []
241 1 | testme
242 self.assertCallStack([("__ror__", (testme, 1))])
244 callLst[:] = []
245 testme ^ 1
246 self.assertCallStack([("__xor__", (testme, 1))])
248 callLst[:] = []
249 1 ^ testme
250 self.assertCallStack([("__rxor__", (testme, 1))])
252 def testListAndDictOps(self):
253 testme = AllTests()
255 # List/dict operations
257 class Empty: pass
259 try:
260 1 in Empty()
261 self.fail('failed, should have raised TypeError')
262 except TypeError:
263 pass
265 callLst[:] = []
266 1 in testme
267 self.assertCallStack([('__contains__', (testme, 1))])
269 callLst[:] = []
270 testme[1]
271 self.assertCallStack([('__getitem__', (testme, 1))])
273 callLst[:] = []
274 testme[1] = 1
275 self.assertCallStack([('__setitem__', (testme, 1, 1))])
277 callLst[:] = []
278 del testme[1]
279 self.assertCallStack([('__delitem__', (testme, 1))])
281 callLst[:] = []
282 testme[:42]
283 self.assertCallStack([('__getitem__', (testme, slice(None, 42)))])
285 callLst[:] = []
286 testme[:42] = "The Answer"
287 self.assertCallStack([('__setitem__', (testme, slice(None, 42),
288 "The Answer"))])
290 callLst[:] = []
291 del testme[:42]
292 self.assertCallStack([('__delitem__', (testme, slice(None, 42)))])
294 callLst[:] = []
295 testme[2:1024:10]
296 self.assertCallStack([('__getitem__', (testme, slice(2, 1024, 10)))])
298 callLst[:] = []
299 testme[2:1024:10] = "A lot"
300 self.assertCallStack([('__setitem__', (testme, slice(2, 1024, 10),
301 "A lot"))])
302 callLst[:] = []
303 del testme[2:1024:10]
304 self.assertCallStack([('__delitem__', (testme, slice(2, 1024, 10)))])
306 callLst[:] = []
307 testme[:42, ..., :24:, 24, 100]
308 self.assertCallStack([('__getitem__', (testme, (slice(None, 42, None),
309 Ellipsis,
310 slice(None, 24, None),
311 24, 100)))])
312 callLst[:] = []
313 testme[:42, ..., :24:, 24, 100] = "Strange"
314 self.assertCallStack([('__setitem__', (testme, (slice(None, 42, None),
315 Ellipsis,
316 slice(None, 24, None),
317 24, 100), "Strange"))])
318 callLst[:] = []
319 del testme[:42, ..., :24:, 24, 100]
320 self.assertCallStack([('__delitem__', (testme, (slice(None, 42, None),
321 Ellipsis,
322 slice(None, 24, None),
323 24, 100)))])
325 def testUnaryOps(self):
326 testme = AllTests()
328 callLst[:] = []
329 -testme
330 self.assertCallStack([('__neg__', (testme,))])
331 callLst[:] = []
332 +testme
333 self.assertCallStack([('__pos__', (testme,))])
334 callLst[:] = []
335 abs(testme)
336 self.assertCallStack([('__abs__', (testme,))])
337 callLst[:] = []
338 int(testme)
339 self.assertCallStack([('__int__', (testme,))])
340 callLst[:] = []
341 float(testme)
342 self.assertCallStack([('__float__', (testme,))])
343 callLst[:] = []
344 oct(testme)
345 self.assertCallStack([('__index__', (testme,))])
346 callLst[:] = []
347 hex(testme)
348 self.assertCallStack([('__index__', (testme,))])
351 def testMisc(self):
352 testme = AllTests()
354 callLst[:] = []
355 hash(testme)
356 self.assertCallStack([('__hash__', (testme,))])
358 callLst[:] = []
359 repr(testme)
360 self.assertCallStack([('__repr__', (testme,))])
362 callLst[:] = []
363 str(testme)
364 self.assertCallStack([('__str__', (testme,))])
366 callLst[:] = []
367 testme == 1
368 self.assertCallStack([('__eq__', (testme, 1))])
370 callLst[:] = []
371 testme < 1
372 self.assertCallStack([('__lt__', (testme, 1))])
374 callLst[:] = []
375 testme > 1
376 self.assertCallStack([('__gt__', (testme, 1))])
378 callLst[:] = []
379 testme != 1
380 self.assertCallStack([('__ne__', (testme, 1))])
382 callLst[:] = []
383 1 == testme
384 self.assertCallStack([('__eq__', (1, testme))])
386 callLst[:] = []
387 1 < testme
388 self.assertCallStack([('__gt__', (1, testme))])
390 callLst[:] = []
391 1 > testme
392 self.assertCallStack([('__lt__', (1, testme))])
394 callLst[:] = []
395 1 != testme
396 self.assertCallStack([('__ne__', (1, testme))])
399 def testGetSetAndDel(self):
400 # Interfering tests
401 class ExtraTests(AllTests):
402 @trackCall
403 def __getattr__(self, *args):
404 return "SomeVal"
406 @trackCall
407 def __setattr__(self, *args):
408 pass
410 @trackCall
411 def __delattr__(self, *args):
412 pass
414 testme = ExtraTests()
416 callLst[:] = []
417 testme.spam
418 self.assertCallStack([('__getattr__', (testme, "spam"))])
420 callLst[:] = []
421 testme.eggs = "spam, spam, spam and ham"
422 self.assertCallStack([('__setattr__', (testme, "eggs",
423 "spam, spam, spam and ham"))])
425 callLst[:] = []
426 del testme.cardinal
427 self.assertCallStack([('__delattr__', (testme, "cardinal"))])
429 def testDel(self):
430 x = []
432 class DelTest:
433 def __del__(self):
434 x.append("crab people, crab people")
435 testme = DelTest()
436 del testme
437 import gc
438 gc.collect()
439 self.assertEquals(["crab people, crab people"], x)
441 def testBadTypeReturned(self):
442 # return values of some method are type-checked
443 class BadTypeClass:
444 def __int__(self):
445 return None
446 __float__ = __int__
447 __str__ = __int__
448 __repr__ = __int__
449 __oct__ = __int__
450 __hex__ = __int__
452 for f in [int, float, str, repr, oct, hex]:
453 self.assertRaises(TypeError, f, BadTypeClass())
455 def testHashStuff(self):
456 # Test correct errors from hash() on objects with comparisons but
457 # no __hash__
459 class C0:
460 pass
462 hash(C0()) # This should work; the next two should raise TypeError
464 class C2:
465 def __eq__(self, other): return 1
467 self.assertRaises(TypeError, hash, C2())
470 def testSFBug532646(self):
471 # Test for SF bug 532646
473 class A:
474 pass
475 A.__call__ = A()
476 a = A()
478 try:
479 a() # This should not segfault
480 except RuntimeError:
481 pass
482 else:
483 self.fail("Failed to raise RuntimeError")
485 def testForExceptionsRaisedInInstanceGetattr2(self):
486 # Tests for exceptions raised in instance_getattr2().
488 def booh(self):
489 raise AttributeError("booh")
491 class A:
492 a = property(booh)
493 try:
494 A().a # Raised AttributeError: A instance has no attribute 'a'
495 except AttributeError as x:
496 if str(x) != "booh":
497 self.fail("attribute error for A().a got masked: %s" % x)
499 class E:
500 __eq__ = property(booh)
501 E() == E() # In debug mode, caused a C-level assert() to fail
503 class I:
504 __init__ = property(booh)
505 try:
506 # In debug mode, printed XXX undetected error and
507 # raises AttributeError
509 except AttributeError as x:
510 pass
511 else:
512 self.fail("attribute error for I.__init__ got masked")
514 def testHashComparisonOfMethods(self):
515 # Test comparison and hash of methods
516 class A:
517 def __init__(self, x):
518 self.x = x
519 def f(self):
520 pass
521 def g(self):
522 pass
523 def __eq__(self, other):
524 return self.x == other.x
525 def __hash__(self):
526 return self.x
527 class B(A):
528 pass
530 a1 = A(1)
531 a2 = A(2)
532 self.assertEquals(a1.f, a1.f)
533 self.assertNotEquals(a1.f, a2.f)
534 self.assertNotEquals(a1.f, a1.g)
535 self.assertEquals(a1.f, A(1).f)
536 self.assertEquals(hash(a1.f), hash(a1.f))
537 self.assertEquals(hash(a1.f), hash(A(1).f))
539 self.assertNotEquals(A.f, a1.f)
540 self.assertNotEquals(A.f, A.g)
541 self.assertEquals(B.f, A.f)
542 self.assertEquals(hash(B.f), hash(A.f))
544 # the following triggers a SystemError in 2.4
545 a = A(hash(A.f)^(-1))
546 hash(a.f)
548 def test_main():
549 support.run_unittest(ClassTests)
551 if __name__=='__main__':
552 test_main()