1"Test the functionality of Python classes implementing operators."
2
3import unittest
4
5from test import test_support
6
7testmeths = [
8
9# Binary operations
10    "add",
11    "radd",
12    "sub",
13    "rsub",
14    "mul",
15    "rmul",
16    "div",
17    "rdiv",
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",
34
35# List/dict operations
36    "contains",
37    "getitem",
38    "getslice",
39    "setitem",
40    "setslice",
41    "delitem",
42    "delslice",
43
44# Unary operations
45    "neg",
46    "pos",
47    "abs",
48
49# generic operations
50    "init",
51    ]
52
53# These need to return something other than None
54#    "coerce",
55#    "hash",
56#    "str",
57#    "repr",
58#    "int",
59#    "long",
60#    "float",
61#    "oct",
62#    "hex",
63
64# These are separate because they can influence the test of other methods.
65#    "getattr",
66#    "setattr",
67#    "delattr",
68
69callLst = []
70def trackCall(f):
71    def track(*args, **kwargs):
72        callLst.append((f.__name__, args))
73        return f(*args, **kwargs)
74    return track
75
76class AllTests:
77    trackCall = trackCall
78
79    @trackCall
80    def __coerce__(self, *args):
81        return (self,) + args
82
83    @trackCall
84    def __hash__(self, *args):
85        return hash(id(self))
86
87    @trackCall
88    def __str__(self, *args):
89        return "AllTests"
90
91    @trackCall
92    def __repr__(self, *args):
93        return "AllTests"
94
95    @trackCall
96    def __int__(self, *args):
97        return 1
98
99    @trackCall
100    def __float__(self, *args):
101        return 1.0
102
103    @trackCall
104    def __long__(self, *args):
105        return 1L
106
107    @trackCall
108    def __oct__(self, *args):
109        return '01'
110
111    @trackCall
112    def __hex__(self, *args):
113        return '0x1'
114
115    @trackCall
116    def __cmp__(self, *args):
117        return 0
118
119# Synthesize all the other AllTests methods from the names in testmeths.
120
121method_template = """\
122@trackCall
123def __%(method)s__(self, *args):
124    pass
125"""
126
127for method in testmeths:
128    exec method_template % locals() in AllTests.__dict__
129
130del method, method_template
131
132class ClassTests(unittest.TestCase):
133    def setUp(self):
134        callLst[:] = []
135
136    def assertCallStack(self, expected_calls):
137        actualCallList = callLst[:]  # need to copy because the comparison below will add
138                                     # additional calls to callLst
139        if expected_calls != actualCallList:
140            self.fail("Expected call list:\n  %s\ndoes not match actual call list\n  %s" %
141                      (expected_calls, actualCallList))
142
143    def testInit(self):
144        foo = AllTests()
145        self.assertCallStack([("__init__", (foo,))])
146
147    def testBinaryOps(self):
148        testme = AllTests()
149        # Binary operations
150
151        callLst[:] = []
152        testme + 1
153        self.assertCallStack([("__coerce__", (testme, 1)), ("__add__", (testme, 1))])
154
155        callLst[:] = []
156        1 + testme
157        self.assertCallStack([("__coerce__", (testme, 1)), ("__radd__", (testme, 1))])
158
159        callLst[:] = []
160        testme - 1
161        self.assertCallStack([("__coerce__", (testme, 1)), ("__sub__", (testme, 1))])
162
163        callLst[:] = []
164        1 - testme
165        self.assertCallStack([("__coerce__", (testme, 1)), ("__rsub__", (testme, 1))])
166
167        callLst[:] = []
168        testme * 1
169        self.assertCallStack([("__coerce__", (testme, 1)), ("__mul__", (testme, 1))])
170
171        callLst[:] = []
172        1 * testme
173        self.assertCallStack([("__coerce__", (testme, 1)), ("__rmul__", (testme, 1))])
174
175        if 1/2 == 0:
176            callLst[:] = []
177            testme / 1
178            self.assertCallStack([("__coerce__", (testme, 1)), ("__div__", (testme, 1))])
179
180
181            callLst[:] = []
182            1 / testme
183            self.assertCallStack([("__coerce__", (testme, 1)), ("__rdiv__", (testme, 1))])
184
185        callLst[:] = []
186        testme % 1
187        self.assertCallStack([("__coerce__", (testme, 1)), ("__mod__", (testme, 1))])
188
189        callLst[:] = []
190        1 % testme
191        self.assertCallStack([("__coerce__", (testme, 1)), ("__rmod__", (testme, 1))])
192
193
194        callLst[:] = []
195        divmod(testme,1)
196        self.assertCallStack([("__coerce__", (testme, 1)), ("__divmod__", (testme, 1))])
197
198        callLst[:] = []
199        divmod(1, testme)
200        self.assertCallStack([("__coerce__", (testme, 1)), ("__rdivmod__", (testme, 1))])
201
202        callLst[:] = []
203        testme ** 1
204        self.assertCallStack([("__coerce__", (testme, 1)), ("__pow__", (testme, 1))])
205
206        callLst[:] = []
207        1 ** testme
208        self.assertCallStack([("__coerce__", (testme, 1)), ("__rpow__", (testme, 1))])
209
210        callLst[:] = []
211        testme >> 1
212        self.assertCallStack([("__coerce__", (testme, 1)), ("__rshift__", (testme, 1))])
213
214        callLst[:] = []
215        1 >> testme
216        self.assertCallStack([("__coerce__", (testme, 1)), ("__rrshift__", (testme, 1))])
217
218        callLst[:] = []
219        testme << 1
220        self.assertCallStack([("__coerce__", (testme, 1)), ("__lshift__", (testme, 1))])
221
222        callLst[:] = []
223        1 << testme
224        self.assertCallStack([("__coerce__", (testme, 1)), ("__rlshift__", (testme, 1))])
225
226        callLst[:] = []
227        testme & 1
228        self.assertCallStack([("__coerce__", (testme, 1)), ("__and__", (testme, 1))])
229
230        callLst[:] = []
231        1 & testme
232        self.assertCallStack([("__coerce__", (testme, 1)), ("__rand__", (testme, 1))])
233
234        callLst[:] = []
235        testme | 1
236        self.assertCallStack([("__coerce__", (testme, 1)), ("__or__", (testme, 1))])
237
238        callLst[:] = []
239        1 | testme
240        self.assertCallStack([("__coerce__", (testme, 1)), ("__ror__", (testme, 1))])
241
242        callLst[:] = []
243        testme ^ 1
244        self.assertCallStack([("__coerce__", (testme, 1)), ("__xor__", (testme, 1))])
245
246        callLst[:] = []
247        1 ^ testme
248        self.assertCallStack([("__coerce__", (testme, 1)), ("__rxor__", (testme, 1))])
249
250    def testListAndDictOps(self):
251        testme = AllTests()
252
253        # List/dict operations
254
255        class Empty: pass
256
257        try:
258            1 in Empty()
259            self.fail('failed, should have raised TypeError')
260        except TypeError:
261            pass
262
263        callLst[:] = []
264        1 in testme
265        self.assertCallStack([('__contains__', (testme, 1))])
266
267        callLst[:] = []
268        testme[1]
269        self.assertCallStack([('__getitem__', (testme, 1))])
270
271        callLst[:] = []
272        testme[1] = 1
273        self.assertCallStack([('__setitem__', (testme, 1, 1))])
274
275        callLst[:] = []
276        del testme[1]
277        self.assertCallStack([('__delitem__', (testme, 1))])
278
279        callLst[:] = []
280        testme[:42]
281        self.assertCallStack([('__getslice__', (testme, 0, 42))])
282
283        callLst[:] = []
284        testme[:42] = "The Answer"
285        self.assertCallStack([('__setslice__', (testme, 0, 42, "The Answer"))])
286
287        callLst[:] = []
288        del testme[:42]
289        self.assertCallStack([('__delslice__', (testme, 0, 42))])
290
291        callLst[:] = []
292        testme[2:1024:10]
293        self.assertCallStack([('__getitem__', (testme, slice(2, 1024, 10)))])
294
295        callLst[:] = []
296        testme[2:1024:10] = "A lot"
297        self.assertCallStack([('__setitem__', (testme, slice(2, 1024, 10),
298                                                                    "A lot"))])
299        callLst[:] = []
300        del testme[2:1024:10]
301        self.assertCallStack([('__delitem__', (testme, slice(2, 1024, 10)))])
302
303        callLst[:] = []
304        testme[:42, ..., :24:, 24, 100]
305        self.assertCallStack([('__getitem__', (testme, (slice(None, 42, None),
306                                                        Ellipsis,
307                                                        slice(None, 24, None),
308                                                        24, 100)))])
309        callLst[:] = []
310        testme[:42, ..., :24:, 24, 100] = "Strange"
311        self.assertCallStack([('__setitem__', (testme, (slice(None, 42, None),
312                                                        Ellipsis,
313                                                        slice(None, 24, None),
314                                                        24, 100), "Strange"))])
315        callLst[:] = []
316        del testme[:42, ..., :24:, 24, 100]
317        self.assertCallStack([('__delitem__', (testme, (slice(None, 42, None),
318                                                        Ellipsis,
319                                                        slice(None, 24, None),
320                                                        24, 100)))])
321
322        # Now remove the slice hooks to see if converting normal slices to
323        #  slice object works.
324
325        getslice = AllTests.__getslice__
326        del AllTests.__getslice__
327        setslice = AllTests.__setslice__
328        del AllTests.__setslice__
329        delslice = AllTests.__delslice__
330        del AllTests.__delslice__
331
332        # XXX when using new-style classes the slice testme[:42] produces
333        #  slice(None, 42, None) instead of slice(0, 42, None). py3k will have
334        #  to change this test.
335        callLst[:] = []
336        testme[:42]
337        self.assertCallStack([('__getitem__', (testme, slice(0, 42, None)))])
338
339        callLst[:] = []
340        testme[:42] = "The Answer"
341        self.assertCallStack([('__setitem__', (testme, slice(0, 42, None),
342                                                                "The Answer"))])
343        callLst[:] = []
344        del testme[:42]
345        self.assertCallStack([('__delitem__', (testme, slice(0, 42, None)))])
346
347        # Restore the slice methods, or the tests will fail with regrtest -R.
348        AllTests.__getslice__ = getslice
349        AllTests.__setslice__ = setslice
350        AllTests.__delslice__ = delslice
351
352
353    def testUnaryOps(self):
354        testme = AllTests()
355
356        callLst[:] = []
357        -testme
358        self.assertCallStack([('__neg__', (testme,))])
359        callLst[:] = []
360        +testme
361        self.assertCallStack([('__pos__', (testme,))])
362        callLst[:] = []
363        abs(testme)
364        self.assertCallStack([('__abs__', (testme,))])
365        callLst[:] = []
366        int(testme)
367        self.assertCallStack([('__int__', (testme,))])
368        callLst[:] = []
369        long(testme)
370        self.assertCallStack([('__long__', (testme,))])
371        callLst[:] = []
372        float(testme)
373        self.assertCallStack([('__float__', (testme,))])
374        callLst[:] = []
375        oct(testme)
376        self.assertCallStack([('__oct__', (testme,))])
377        callLst[:] = []
378        hex(testme)
379        self.assertCallStack([('__hex__', (testme,))])
380
381
382    def testMisc(self):
383        testme = AllTests()
384
385        callLst[:] = []
386        hash(testme)
387        self.assertCallStack([('__hash__', (testme,))])
388
389        callLst[:] = []
390        repr(testme)
391        self.assertCallStack([('__repr__', (testme,))])
392
393        callLst[:] = []
394        str(testme)
395        self.assertCallStack([('__str__', (testme,))])
396
397        callLst[:] = []
398        testme == 1
399        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
400
401        callLst[:] = []
402        testme < 1
403        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
404
405        callLst[:] = []
406        testme > 1
407        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
408
409        callLst[:] = []
410        eval('testme <> 1')  # XXX kill this in py3k
411        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
412
413        callLst[:] = []
414        testme != 1
415        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
416
417        callLst[:] = []
418        1 == testme
419        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
420
421        callLst[:] = []
422        1 < testme
423        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
424
425        callLst[:] = []
426        1 > testme
427        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
428
429        callLst[:] = []
430        eval('1 <> testme')
431        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
432
433        callLst[:] = []
434        1 != testme
435        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
436
437
438    def testGetSetAndDel(self):
439        # Interfering tests
440        class ExtraTests(AllTests):
441            @trackCall
442            def __getattr__(self, *args):
443                return "SomeVal"
444
445            @trackCall
446            def __setattr__(self, *args):
447                pass
448
449            @trackCall
450            def __delattr__(self, *args):
451                pass
452
453        testme = ExtraTests()
454
455        callLst[:] = []
456        testme.spam
457        self.assertCallStack([('__getattr__', (testme, "spam"))])
458
459        callLst[:] = []
460        testme.eggs = "spam, spam, spam and ham"
461        self.assertCallStack([('__setattr__', (testme, "eggs",
462                                               "spam, spam, spam and ham"))])
463
464        callLst[:] = []
465        del testme.cardinal
466        self.assertCallStack([('__delattr__', (testme, "cardinal"))])
467
468    def testDel(self):
469        x = []
470
471        class DelTest:
472            def __del__(self):
473                x.append("crab people, crab people")
474        testme = DelTest()
475        del testme
476        import gc
477        gc.collect()
478        self.assertEqual(["crab people, crab people"], x)
479
480    def testBadTypeReturned(self):
481        # return values of some method are type-checked
482        class BadTypeClass:
483            def __int__(self):
484                return None
485            __float__ = __int__
486            __long__ = __int__
487            __str__ = __int__
488            __repr__ = __int__
489            __oct__ = __int__
490            __hex__ = __int__
491
492        for f in [int, float, long, str, repr, oct, hex]:
493            self.assertRaises(TypeError, f, BadTypeClass())
494
495    def testMixIntsAndLongs(self):
496        # mixing up ints and longs is okay
497        class IntLongMixClass:
498            @trackCall
499            def __int__(self):
500                return 42L
501
502            @trackCall
503            def __long__(self):
504                return 64
505
506        mixIntAndLong = IntLongMixClass()
507
508        callLst[:] = []
509        as_int = int(mixIntAndLong)
510        self.assertEqual(type(as_int), long)
511        self.assertEqual(as_int, 42L)
512        self.assertCallStack([('__int__', (mixIntAndLong,))])
513
514        callLst[:] = []
515        as_long = long(mixIntAndLong)
516        self.assertEqual(type(as_long), long)
517        self.assertEqual(as_long, 64)
518        self.assertCallStack([('__long__', (mixIntAndLong,))])
519
520    def testHashStuff(self):
521        # Test correct errors from hash() on objects with comparisons but
522        #  no __hash__
523
524        class C0:
525            pass
526
527        hash(C0()) # This should work; the next two should raise TypeError
528
529        class C1:
530            def __cmp__(self, other): return 0
531
532        self.assertRaises(TypeError, hash, C1())
533
534        class C2:
535            def __eq__(self, other): return 1
536
537        self.assertRaises(TypeError, hash, C2())
538
539
540    def testSFBug532646(self):
541        # Test for SF bug 532646
542
543        class A:
544            pass
545        A.__call__ = A()
546        a = A()
547
548        try:
549            a() # This should not segfault
550        except RuntimeError:
551            pass
552        else:
553            self.fail("Failed to raise RuntimeError")
554
555    def testForExceptionsRaisedInInstanceGetattr2(self):
556        # Tests for exceptions raised in instance_getattr2().
557
558        def booh(self):
559            raise AttributeError("booh")
560
561        class A:
562            a = property(booh)
563        try:
564            A().a # Raised AttributeError: A instance has no attribute 'a'
565        except AttributeError, x:
566            if str(x) != "booh":
567                self.fail("attribute error for A().a got masked: %s" % x)
568
569        class E:
570            __eq__ = property(booh)
571        E() == E() # In debug mode, caused a C-level assert() to fail
572
573        class I:
574            __init__ = property(booh)
575        try:
576            # In debug mode, printed XXX undetected error and
577            #  raises AttributeError
578            I()
579        except AttributeError, x:
580            pass
581        else:
582            self.fail("attribute error for I.__init__ got masked")
583
584    def testHashComparisonOfMethods(self):
585        # Test comparison and hash of methods
586        class A:
587            def __init__(self, x):
588                self.x = x
589            def f(self):
590                pass
591            def g(self):
592                pass
593            def __eq__(self, other):
594                return self.x == other.x
595            def __hash__(self):
596                return self.x
597        class B(A):
598            pass
599
600        a1 = A(1)
601        a2 = A(2)
602        self.assertEqual(a1.f, a1.f)
603        self.assertNotEqual(a1.f, a2.f)
604        self.assertNotEqual(a1.f, a1.g)
605        self.assertEqual(a1.f, A(1).f)
606        self.assertEqual(hash(a1.f), hash(a1.f))
607        self.assertEqual(hash(a1.f), hash(A(1).f))
608
609        self.assertNotEqual(A.f, a1.f)
610        self.assertNotEqual(A.f, A.g)
611        self.assertEqual(B.f, A.f)
612        self.assertEqual(hash(B.f), hash(A.f))
613
614        # the following triggers a SystemError in 2.4
615        a = A(hash(A.f.im_func)^(-1))
616        hash(a.f)
617
618def test_main():
619    with test_support.check_py3k_warnings(
620            (".+__(get|set|del)slice__ has been removed", DeprecationWarning),
621            ("classic int division", DeprecationWarning),
622            ("<> not supported", DeprecationWarning)):
623        test_support.run_unittest(ClassTests)
624
625if __name__=='__main__':
626    test_main()
627