1"Test the functionality of Python classes implementing operators."
2
3import unittest
4
5
6testmeths = [
7
8# Binary operations
9    "add",
10    "radd",
11    "sub",
12    "rsub",
13    "mul",
14    "rmul",
15    "matmul",
16    "rmatmul",
17    "truediv",
18    "rtruediv",
19    "floordiv",
20    "rfloordiv",
21    "mod",
22    "rmod",
23    "divmod",
24    "rdivmod",
25    "pow",
26    "rpow",
27    "rshift",
28    "rrshift",
29    "lshift",
30    "rlshift",
31    "and",
32    "rand",
33    "or",
34    "ror",
35    "xor",
36    "rxor",
37
38# List/dict operations
39    "contains",
40    "getitem",
41    "setitem",
42    "delitem",
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#    "hash",
55#    "str",
56#    "repr",
57#    "int",
58#    "float",
59
60# These are separate because they can influence the test of other methods.
61#    "getattr",
62#    "setattr",
63#    "delattr",
64
65callLst = []
66def trackCall(f):
67    def track(*args, **kwargs):
68        callLst.append((f.__name__, args))
69        return f(*args, **kwargs)
70    return track
71
72statictests = """
73@trackCall
74def __hash__(self, *args):
75    return hash(id(self))
76
77@trackCall
78def __str__(self, *args):
79    return "AllTests"
80
81@trackCall
82def __repr__(self, *args):
83    return "AllTests"
84
85@trackCall
86def __int__(self, *args):
87    return 1
88
89@trackCall
90def __index__(self, *args):
91    return 1
92
93@trackCall
94def __float__(self, *args):
95    return 1.0
96
97@trackCall
98def __eq__(self, *args):
99    return True
100
101@trackCall
102def __ne__(self, *args):
103    return False
104
105@trackCall
106def __lt__(self, *args):
107    return False
108
109@trackCall
110def __le__(self, *args):
111    return True
112
113@trackCall
114def __gt__(self, *args):
115    return False
116
117@trackCall
118def __ge__(self, *args):
119    return True
120"""
121
122# Synthesize all the other AllTests methods from the names in testmeths.
123
124method_template = """\
125@trackCall
126def __%s__(self, *args):
127    pass
128"""
129
130d = {}
131exec(statictests, globals(), d)
132for method in testmeths:
133    exec(method_template % method, globals(), d)
134AllTests = type("AllTests", (object,), d)
135del d, statictests, method, method_template
136
137class ClassTests(unittest.TestCase):
138    def setUp(self):
139        callLst[:] = []
140
141    def assertCallStack(self, expected_calls):
142        actualCallList = callLst[:]  # need to copy because the comparison below will add
143                                     # additional calls to callLst
144        if expected_calls != actualCallList:
145            self.fail("Expected call list:\n  %s\ndoes not match actual call list\n  %s" %
146                      (expected_calls, actualCallList))
147
148    def testInit(self):
149        foo = AllTests()
150        self.assertCallStack([("__init__", (foo,))])
151
152    def testBinaryOps(self):
153        testme = AllTests()
154        # Binary operations
155
156        callLst[:] = []
157        testme + 1
158        self.assertCallStack([("__add__", (testme, 1))])
159
160        callLst[:] = []
161        1 + testme
162        self.assertCallStack([("__radd__", (testme, 1))])
163
164        callLst[:] = []
165        testme - 1
166        self.assertCallStack([("__sub__", (testme, 1))])
167
168        callLst[:] = []
169        1 - testme
170        self.assertCallStack([("__rsub__", (testme, 1))])
171
172        callLst[:] = []
173        testme * 1
174        self.assertCallStack([("__mul__", (testme, 1))])
175
176        callLst[:] = []
177        1 * testme
178        self.assertCallStack([("__rmul__", (testme, 1))])
179
180        callLst[:] = []
181        testme @ 1
182        self.assertCallStack([("__matmul__", (testme, 1))])
183
184        callLst[:] = []
185        1 @ testme
186        self.assertCallStack([("__rmatmul__", (testme, 1))])
187
188        callLst[:] = []
189        testme / 1
190        self.assertCallStack([("__truediv__", (testme, 1))])
191
192
193        callLst[:] = []
194        1 / testme
195        self.assertCallStack([("__rtruediv__", (testme, 1))])
196
197        callLst[:] = []
198        testme // 1
199        self.assertCallStack([("__floordiv__", (testme, 1))])
200
201
202        callLst[:] = []
203        1 // testme
204        self.assertCallStack([("__rfloordiv__", (testme, 1))])
205
206        callLst[:] = []
207        testme % 1
208        self.assertCallStack([("__mod__", (testme, 1))])
209
210        callLst[:] = []
211        1 % testme
212        self.assertCallStack([("__rmod__", (testme, 1))])
213
214
215        callLst[:] = []
216        divmod(testme,1)
217        self.assertCallStack([("__divmod__", (testme, 1))])
218
219        callLst[:] = []
220        divmod(1, testme)
221        self.assertCallStack([("__rdivmod__", (testme, 1))])
222
223        callLst[:] = []
224        testme ** 1
225        self.assertCallStack([("__pow__", (testme, 1))])
226
227        callLst[:] = []
228        1 ** testme
229        self.assertCallStack([("__rpow__", (testme, 1))])
230
231        callLst[:] = []
232        testme >> 1
233        self.assertCallStack([("__rshift__", (testme, 1))])
234
235        callLst[:] = []
236        1 >> testme
237        self.assertCallStack([("__rrshift__", (testme, 1))])
238
239        callLst[:] = []
240        testme << 1
241        self.assertCallStack([("__lshift__", (testme, 1))])
242
243        callLst[:] = []
244        1 << testme
245        self.assertCallStack([("__rlshift__", (testme, 1))])
246
247        callLst[:] = []
248        testme & 1
249        self.assertCallStack([("__and__", (testme, 1))])
250
251        callLst[:] = []
252        1 & testme
253        self.assertCallStack([("__rand__", (testme, 1))])
254
255        callLst[:] = []
256        testme | 1
257        self.assertCallStack([("__or__", (testme, 1))])
258
259        callLst[:] = []
260        1 | testme
261        self.assertCallStack([("__ror__", (testme, 1))])
262
263        callLst[:] = []
264        testme ^ 1
265        self.assertCallStack([("__xor__", (testme, 1))])
266
267        callLst[:] = []
268        1 ^ testme
269        self.assertCallStack([("__rxor__", (testme, 1))])
270
271    def testListAndDictOps(self):
272        testme = AllTests()
273
274        # List/dict operations
275
276        class Empty: pass
277
278        try:
279            1 in Empty()
280            self.fail('failed, should have raised TypeError')
281        except TypeError:
282            pass
283
284        callLst[:] = []
285        1 in testme
286        self.assertCallStack([('__contains__', (testme, 1))])
287
288        callLst[:] = []
289        testme[1]
290        self.assertCallStack([('__getitem__', (testme, 1))])
291
292        callLst[:] = []
293        testme[1] = 1
294        self.assertCallStack([('__setitem__', (testme, 1, 1))])
295
296        callLst[:] = []
297        del testme[1]
298        self.assertCallStack([('__delitem__', (testme, 1))])
299
300        callLst[:] = []
301        testme[:42]
302        self.assertCallStack([('__getitem__', (testme, slice(None, 42)))])
303
304        callLst[:] = []
305        testme[:42] = "The Answer"
306        self.assertCallStack([('__setitem__', (testme, slice(None, 42),
307                                               "The Answer"))])
308
309        callLst[:] = []
310        del testme[:42]
311        self.assertCallStack([('__delitem__', (testme, slice(None, 42)))])
312
313        callLst[:] = []
314        testme[2:1024:10]
315        self.assertCallStack([('__getitem__', (testme, slice(2, 1024, 10)))])
316
317        callLst[:] = []
318        testme[2:1024:10] = "A lot"
319        self.assertCallStack([('__setitem__', (testme, slice(2, 1024, 10),
320                                                                    "A lot"))])
321        callLst[:] = []
322        del testme[2:1024:10]
323        self.assertCallStack([('__delitem__', (testme, slice(2, 1024, 10)))])
324
325        callLst[:] = []
326        testme[:42, ..., :24:, 24, 100]
327        self.assertCallStack([('__getitem__', (testme, (slice(None, 42, None),
328                                                        Ellipsis,
329                                                        slice(None, 24, None),
330                                                        24, 100)))])
331        callLst[:] = []
332        testme[:42, ..., :24:, 24, 100] = "Strange"
333        self.assertCallStack([('__setitem__', (testme, (slice(None, 42, None),
334                                                        Ellipsis,
335                                                        slice(None, 24, None),
336                                                        24, 100), "Strange"))])
337        callLst[:] = []
338        del testme[:42, ..., :24:, 24, 100]
339        self.assertCallStack([('__delitem__', (testme, (slice(None, 42, None),
340                                                        Ellipsis,
341                                                        slice(None, 24, None),
342                                                        24, 100)))])
343
344    def testUnaryOps(self):
345        testme = AllTests()
346
347        callLst[:] = []
348        -testme
349        self.assertCallStack([('__neg__', (testme,))])
350        callLst[:] = []
351        +testme
352        self.assertCallStack([('__pos__', (testme,))])
353        callLst[:] = []
354        abs(testme)
355        self.assertCallStack([('__abs__', (testme,))])
356        callLst[:] = []
357        int(testme)
358        self.assertCallStack([('__int__', (testme,))])
359        callLst[:] = []
360        float(testme)
361        self.assertCallStack([('__float__', (testme,))])
362        callLst[:] = []
363        oct(testme)
364        self.assertCallStack([('__index__', (testme,))])
365        callLst[:] = []
366        hex(testme)
367        self.assertCallStack([('__index__', (testme,))])
368
369
370    def testMisc(self):
371        testme = AllTests()
372
373        callLst[:] = []
374        hash(testme)
375        self.assertCallStack([('__hash__', (testme,))])
376
377        callLst[:] = []
378        repr(testme)
379        self.assertCallStack([('__repr__', (testme,))])
380
381        callLst[:] = []
382        str(testme)
383        self.assertCallStack([('__str__', (testme,))])
384
385        callLst[:] = []
386        testme == 1
387        self.assertCallStack([('__eq__', (testme, 1))])
388
389        callLst[:] = []
390        testme < 1
391        self.assertCallStack([('__lt__', (testme, 1))])
392
393        callLst[:] = []
394        testme > 1
395        self.assertCallStack([('__gt__', (testme, 1))])
396
397        callLst[:] = []
398        testme != 1
399        self.assertCallStack([('__ne__', (testme, 1))])
400
401        callLst[:] = []
402        1 == testme
403        self.assertCallStack([('__eq__', (1, testme))])
404
405        callLst[:] = []
406        1 < testme
407        self.assertCallStack([('__gt__', (1, testme))])
408
409        callLst[:] = []
410        1 > testme
411        self.assertCallStack([('__lt__', (1, testme))])
412
413        callLst[:] = []
414        1 != testme
415        self.assertCallStack([('__ne__', (1, testme))])
416
417
418    def testGetSetAndDel(self):
419        # Interfering tests
420        class ExtraTests(AllTests):
421            @trackCall
422            def __getattr__(self, *args):
423                return "SomeVal"
424
425            @trackCall
426            def __setattr__(self, *args):
427                pass
428
429            @trackCall
430            def __delattr__(self, *args):
431                pass
432
433        testme = ExtraTests()
434
435        callLst[:] = []
436        testme.spam
437        self.assertCallStack([('__getattr__', (testme, "spam"))])
438
439        callLst[:] = []
440        testme.eggs = "spam, spam, spam and ham"
441        self.assertCallStack([('__setattr__', (testme, "eggs",
442                                               "spam, spam, spam and ham"))])
443
444        callLst[:] = []
445        del testme.cardinal
446        self.assertCallStack([('__delattr__', (testme, "cardinal"))])
447
448    def testDel(self):
449        x = []
450
451        class DelTest:
452            def __del__(self):
453                x.append("crab people, crab people")
454        testme = DelTest()
455        del testme
456        import gc
457        gc.collect()
458        self.assertEqual(["crab people, crab people"], x)
459
460    def testBadTypeReturned(self):
461        # return values of some method are type-checked
462        class BadTypeClass:
463            def __int__(self):
464                return None
465            __float__ = __int__
466            __complex__ = __int__
467            __str__ = __int__
468            __repr__ = __int__
469            __bytes__ = __int__
470            __bool__ = __int__
471            __index__ = __int__
472        def index(x):
473            return [][x]
474
475        for f in [float, complex, str, repr, bytes, bin, oct, hex, bool, index]:
476            self.assertRaises(TypeError, f, BadTypeClass())
477
478    def testHashStuff(self):
479        # Test correct errors from hash() on objects with comparisons but
480        #  no __hash__
481
482        class C0:
483            pass
484
485        hash(C0()) # This should work; the next two should raise TypeError
486
487        class C2:
488            def __eq__(self, other): return 1
489
490        self.assertRaises(TypeError, hash, C2())
491
492
493    def testSFBug532646(self):
494        # Test for SF bug 532646
495
496        class A:
497            pass
498        A.__call__ = A()
499        a = A()
500
501        try:
502            a() # This should not segfault
503        except RecursionError:
504            pass
505        else:
506            self.fail("Failed to raise RecursionError")
507
508    def testForExceptionsRaisedInInstanceGetattr2(self):
509        # Tests for exceptions raised in instance_getattr2().
510
511        def booh(self):
512            raise AttributeError("booh")
513
514        class A:
515            a = property(booh)
516        try:
517            A().a # Raised AttributeError: A instance has no attribute 'a'
518        except AttributeError as x:
519            if str(x) != "booh":
520                self.fail("attribute error for A().a got masked: %s" % x)
521
522        class E:
523            __eq__ = property(booh)
524        E() == E() # In debug mode, caused a C-level assert() to fail
525
526        class I:
527            __init__ = property(booh)
528        try:
529            # In debug mode, printed XXX undetected error and
530            #  raises AttributeError
531            I()
532        except AttributeError as x:
533            pass
534        else:
535            self.fail("attribute error for I.__init__ got masked")
536
537    def testHashComparisonOfMethods(self):
538        # Test comparison and hash of methods
539        class A:
540            def __init__(self, x):
541                self.x = x
542            def f(self):
543                pass
544            def g(self):
545                pass
546            def __eq__(self, other):
547                return self.x == other.x
548            def __hash__(self):
549                return self.x
550        class B(A):
551            pass
552
553        a1 = A(1)
554        a2 = A(2)
555        self.assertEqual(a1.f, a1.f)
556        self.assertNotEqual(a1.f, a2.f)
557        self.assertNotEqual(a1.f, a1.g)
558        self.assertEqual(a1.f, A(1).f)
559        self.assertEqual(hash(a1.f), hash(a1.f))
560        self.assertEqual(hash(a1.f), hash(A(1).f))
561
562        self.assertNotEqual(A.f, a1.f)
563        self.assertNotEqual(A.f, A.g)
564        self.assertEqual(B.f, A.f)
565        self.assertEqual(hash(B.f), hash(A.f))
566
567        # the following triggers a SystemError in 2.4
568        a = A(hash(A.f)^(-1))
569        hash(a.f)
570
571if __name__ == '__main__':
572    unittest.main()
573