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    @test_support.cpython_only
354    def testDelItem(self):
355        class A:
356            ok = False
357            def __delitem__(self, key):
358                self.ok = True
359        a = A()
360        # Subtle: we need to call PySequence_SetItem, not PyMapping_SetItem.
361        from _testcapi import sequence_delitem
362        sequence_delitem(a, 2)
363        self.assertTrue(a.ok)
364
365
366    def testUnaryOps(self):
367        testme = AllTests()
368
369        callLst[:] = []
370        -testme
371        self.assertCallStack([('__neg__', (testme,))])
372        callLst[:] = []
373        +testme
374        self.assertCallStack([('__pos__', (testme,))])
375        callLst[:] = []
376        abs(testme)
377        self.assertCallStack([('__abs__', (testme,))])
378        callLst[:] = []
379        int(testme)
380        self.assertCallStack([('__int__', (testme,))])
381        callLst[:] = []
382        long(testme)
383        self.assertCallStack([('__long__', (testme,))])
384        callLst[:] = []
385        float(testme)
386        self.assertCallStack([('__float__', (testme,))])
387        callLst[:] = []
388        oct(testme)
389        self.assertCallStack([('__oct__', (testme,))])
390        callLst[:] = []
391        hex(testme)
392        self.assertCallStack([('__hex__', (testme,))])
393
394
395    def testMisc(self):
396        testme = AllTests()
397
398        callLst[:] = []
399        hash(testme)
400        self.assertCallStack([('__hash__', (testme,))])
401
402        callLst[:] = []
403        repr(testme)
404        self.assertCallStack([('__repr__', (testme,))])
405
406        callLst[:] = []
407        str(testme)
408        self.assertCallStack([('__str__', (testme,))])
409
410        callLst[:] = []
411        testme == 1
412        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
413
414        callLst[:] = []
415        testme < 1
416        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
417
418        callLst[:] = []
419        testme > 1
420        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
421
422        callLst[:] = []
423        eval('testme <> 1')  # XXX kill this in py3k
424        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
425
426        callLst[:] = []
427        testme != 1
428        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (testme, 1))])
429
430        callLst[:] = []
431        1 == testme
432        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
433
434        callLst[:] = []
435        1 < testme
436        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
437
438        callLst[:] = []
439        1 > testme
440        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
441
442        callLst[:] = []
443        eval('1 <> testme')
444        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
445
446        callLst[:] = []
447        1 != testme
448        self.assertCallStack([("__coerce__", (testme, 1)), ('__cmp__', (1, testme))])
449
450
451    def testGetSetAndDel(self):
452        # Interfering tests
453        class ExtraTests(AllTests):
454            @trackCall
455            def __getattr__(self, *args):
456                return "SomeVal"
457
458            @trackCall
459            def __setattr__(self, *args):
460                pass
461
462            @trackCall
463            def __delattr__(self, *args):
464                pass
465
466        testme = ExtraTests()
467
468        callLst[:] = []
469        testme.spam
470        self.assertCallStack([('__getattr__', (testme, "spam"))])
471
472        callLst[:] = []
473        testme.eggs = "spam, spam, spam and ham"
474        self.assertCallStack([('__setattr__', (testme, "eggs",
475                                               "spam, spam, spam and ham"))])
476
477        callLst[:] = []
478        del testme.cardinal
479        self.assertCallStack([('__delattr__', (testme, "cardinal"))])
480
481    def testDel(self):
482        x = []
483
484        class DelTest:
485            def __del__(self):
486                x.append("crab people, crab people")
487        testme = DelTest()
488        del testme
489        import gc
490        gc.collect()
491        self.assertEqual(["crab people, crab people"], x)
492
493    def testBadTypeReturned(self):
494        # return values of some method are type-checked
495        class BadTypeClass:
496            def __int__(self):
497                return None
498            __float__ = __int__
499            __long__ = __int__
500            __str__ = __int__
501            __repr__ = __int__
502            __oct__ = __int__
503            __hex__ = __int__
504
505        for f in [int, float, long, str, repr, oct, hex]:
506            self.assertRaises(TypeError, f, BadTypeClass())
507
508    def testMixIntsAndLongs(self):
509        # mixing up ints and longs is okay
510        class IntLongMixClass:
511            @trackCall
512            def __int__(self):
513                return 42L
514
515            @trackCall
516            def __long__(self):
517                return 64
518
519        mixIntAndLong = IntLongMixClass()
520
521        callLst[:] = []
522        as_int = int(mixIntAndLong)
523        self.assertEqual(type(as_int), long)
524        self.assertEqual(as_int, 42L)
525        self.assertCallStack([('__int__', (mixIntAndLong,))])
526
527        callLst[:] = []
528        as_long = long(mixIntAndLong)
529        self.assertEqual(type(as_long), long)
530        self.assertEqual(as_long, 64)
531        self.assertCallStack([('__long__', (mixIntAndLong,))])
532
533    def testHashStuff(self):
534        # Test correct errors from hash() on objects with comparisons but
535        #  no __hash__
536
537        class C0:
538            pass
539
540        hash(C0()) # This should work; the next two should raise TypeError
541
542        class C1:
543            def __cmp__(self, other): return 0
544
545        self.assertRaises(TypeError, hash, C1())
546
547        class C2:
548            def __eq__(self, other): return 1
549
550        self.assertRaises(TypeError, hash, C2())
551
552
553    def testSFBug532646(self):
554        # Test for SF bug 532646
555
556        class A:
557            pass
558        A.__call__ = A()
559        a = A()
560
561        try:
562            a() # This should not segfault
563        except RuntimeError:
564            pass
565        else:
566            self.fail("Failed to raise RuntimeError")
567
568    def testForExceptionsRaisedInInstanceGetattr2(self):
569        # Tests for exceptions raised in instance_getattr2().
570
571        def booh(self):
572            raise AttributeError("booh")
573
574        class A:
575            a = property(booh)
576        try:
577            A().a # Raised AttributeError: A instance has no attribute 'a'
578        except AttributeError, x:
579            if str(x) != "booh":
580                self.fail("attribute error for A().a got masked: %s" % x)
581
582        class E:
583            __eq__ = property(booh)
584        E() == E() # In debug mode, caused a C-level assert() to fail
585
586        class I:
587            __init__ = property(booh)
588        try:
589            # In debug mode, printed XXX undetected error and
590            #  raises AttributeError
591            I()
592        except AttributeError, x:
593            pass
594        else:
595            self.fail("attribute error for I.__init__ got masked")
596
597    def testHashComparisonOfMethods(self):
598        # Test comparison and hash of methods
599        class A:
600            def __init__(self, x):
601                self.x = x
602            def f(self):
603                pass
604            def g(self):
605                pass
606            def __eq__(self, other):
607                return self.x == other.x
608            def __hash__(self):
609                return self.x
610        class B(A):
611            pass
612
613        a1 = A(1)
614        a2 = A(2)
615        self.assertEqual(a1.f, a1.f)
616        self.assertNotEqual(a1.f, a2.f)
617        self.assertNotEqual(a1.f, a1.g)
618        self.assertEqual(a1.f, A(1).f)
619        self.assertEqual(hash(a1.f), hash(a1.f))
620        self.assertEqual(hash(a1.f), hash(A(1).f))
621
622        self.assertNotEqual(A.f, a1.f)
623        self.assertNotEqual(A.f, A.g)
624        self.assertEqual(B.f, A.f)
625        self.assertEqual(hash(B.f), hash(A.f))
626
627        # the following triggers a SystemError in 2.4
628        a = A(hash(A.f.im_func)^(-1))
629        hash(a.f)
630
631    def testAttrSlots(self):
632        class C:
633            pass
634        for c in C, C():
635            self.assertRaises(TypeError, type(c).__getattribute__, c, [])
636            self.assertRaises(TypeError, type(c).__setattr__, c, [], [])
637
638def test_main():
639    with test_support.check_py3k_warnings(
640            (".+__(get|set|del)slice__ has been removed", DeprecationWarning),
641            ("classic int division", DeprecationWarning),
642            ("<> not supported", DeprecationWarning)):
643        test_support.run_unittest(ClassTests)
644
645if __name__=='__main__':
646    test_main()
647