python-2.5.2/win32/Lib/test/test_coercion.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 import copy
       
     2 import sys
       
     3 import warnings
       
     4 import unittest
       
     5 from test.test_support import run_unittest, TestFailed
       
     6 
       
     7 # Fake a number that implements numeric methods through __coerce__
       
     8 class CoerceNumber:
       
     9     def __init__(self, arg):
       
    10         self.arg = arg
       
    11 
       
    12     def __repr__(self):
       
    13         return '<CoerceNumber %s>' % repr(self.arg)
       
    14 
       
    15     def __coerce__(self, other):
       
    16         if isinstance(other, CoerceNumber):
       
    17             return self.arg, other.arg
       
    18         else:
       
    19             return (self.arg, other)
       
    20 
       
    21 # New-style class version of CoerceNumber
       
    22 class CoerceTo(object):
       
    23     def __init__(self, arg):
       
    24         self.arg = arg
       
    25     def __coerce__(self, other):
       
    26         if isinstance(other, CoerceTo):
       
    27             return self.arg, other.arg
       
    28         else:
       
    29             return self.arg, other
       
    30 
       
    31 
       
    32 # Fake a number that implements numeric ops through methods.
       
    33 class MethodNumber:
       
    34     def __init__(self,arg):
       
    35         self.arg = arg
       
    36 
       
    37     def __repr__(self):
       
    38         return '<MethodNumber %s>' % repr(self.arg)
       
    39 
       
    40     def __add__(self,other):
       
    41         return self.arg + other
       
    42 
       
    43     def __radd__(self,other):
       
    44         return other + self.arg
       
    45 
       
    46     def __sub__(self,other):
       
    47         return self.arg - other
       
    48 
       
    49     def __rsub__(self,other):
       
    50         return other - self.arg
       
    51 
       
    52     def __mul__(self,other):
       
    53         return self.arg * other
       
    54 
       
    55     def __rmul__(self,other):
       
    56         return other * self.arg
       
    57 
       
    58     def __div__(self,other):
       
    59         return self.arg / other
       
    60 
       
    61     def __rdiv__(self,other):
       
    62         return other / self.arg
       
    63 
       
    64     def __truediv__(self,other):
       
    65         return self.arg / other
       
    66 
       
    67     def __rtruediv__(self,other):
       
    68         return other / self.arg
       
    69 
       
    70     def __floordiv__(self,other):
       
    71         return self.arg // other
       
    72 
       
    73     def __rfloordiv__(self,other):
       
    74         return other // self.arg
       
    75 
       
    76     def __pow__(self,other):
       
    77         return self.arg ** other
       
    78 
       
    79     def __rpow__(self,other):
       
    80         return other ** self.arg
       
    81 
       
    82     def __mod__(self,other):
       
    83         return self.arg % other
       
    84 
       
    85     def __rmod__(self,other):
       
    86         return other % self.arg
       
    87 
       
    88     def __cmp__(self, other):
       
    89         return cmp(self.arg, other)
       
    90 
       
    91 
       
    92 candidates = [2, 2L, 4.0, 2+0j, [1], (2,), None,
       
    93               MethodNumber(2), CoerceNumber(2)]
       
    94 
       
    95 infix_binops = [ '+', '-', '*', '**', '%', '//', '/' ]
       
    96 
       
    97 TE = TypeError
       
    98 # b = both normal and augmented give same result list
       
    99 # s = single result lists for normal and augmented
       
   100 # e = equals other results
       
   101 # result lists: ['+', '-', '*', '**', '%', '//', ('classic /', 'new /')]
       
   102 #                                                ^^^^^^^^^^^^^^^^^^^^^^
       
   103 #                                               2-tuple if results differ
       
   104 #                                                 else only one value
       
   105 infix_results = {
       
   106     # 2
       
   107     (0,0): ('b', [4, 0, 4, 4, 0, 1, (1, 1.0)]),
       
   108     (0,1): ('e', (0,0)),
       
   109     (0,2): ('b', [6.0, -2.0, 8.0, 16.0, 2.0, 0.0, 0.5]),
       
   110     (0,3): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
       
   111     (0,4): ('b', [TE, TE, [1, 1], TE, TE, TE, TE]),
       
   112     (0,5): ('b', [TE, TE, (2, 2), TE, TE, TE, TE]),
       
   113     (0,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   114     (0,7): ('e', (0,0)),
       
   115     (0,8): ('e', (0,0)),
       
   116 
       
   117     # 2L
       
   118     (1,0): ('e', (0,0)),
       
   119     (1,1): ('e', (0,1)),
       
   120     (1,2): ('e', (0,2)),
       
   121     (1,3): ('e', (0,3)),
       
   122     (1,4): ('e', (0,4)),
       
   123     (1,5): ('e', (0,5)),
       
   124     (1,6): ('e', (0,6)),
       
   125     (1,7): ('e', (0,7)),
       
   126     (1,8): ('e', (0,8)),
       
   127 
       
   128     # 4.0
       
   129     (2,0): ('b', [6.0, 2.0, 8.0, 16.0, 0.0, 2.0, 2.0]),
       
   130     (2,1): ('e', (2,0)),
       
   131     (2,2): ('b', [8.0, 0.0, 16.0, 256.0, 0.0, 1.0, 1.0]),
       
   132     (2,3): ('b', [6+0j, 2+0j, 8+0j, 16+0j, 0+0j, 2+0j, 2+0j]),
       
   133     (2,4): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   134     (2,5): ('e', (2,4)),
       
   135     (2,6): ('e', (2,4)),
       
   136     (2,7): ('e', (2,0)),
       
   137     (2,8): ('e', (2,0)),
       
   138 
       
   139     # (2+0j)
       
   140     (3,0): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
       
   141     (3,1): ('e', (3,0)),
       
   142     (3,2): ('b', [6+0j, -2+0j, 8+0j, 16+0j, 2+0j, 0+0j, 0.5+0j]),
       
   143     (3,3): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]),
       
   144     (3,4): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   145     (3,5): ('e', (3,4)),
       
   146     (3,6): ('e', (3,4)),
       
   147     (3,7): ('e', (3,0)),
       
   148     (3,8): ('e', (3,0)),
       
   149 
       
   150     # [1]
       
   151     (4,0): ('b', [TE, TE, [1, 1], TE, TE, TE, TE]),
       
   152     (4,1): ('e', (4,0)),
       
   153     (4,2): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   154     (4,3): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   155     (4,4): ('b', [[1, 1], TE, TE, TE, TE, TE, TE]),
       
   156     (4,5): ('s', [TE, TE, TE, TE, TE, TE, TE], [[1, 2], TE, TE, TE, TE, TE, TE]),
       
   157     (4,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   158     (4,7): ('e', (4,0)),
       
   159     (4,8): ('e', (4,0)),
       
   160 
       
   161     # (2,)
       
   162     (5,0): ('b', [TE, TE, (2, 2), TE, TE, TE, TE]),
       
   163     (5,1): ('e', (5,0)),
       
   164     (5,2): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   165     (5,3): ('e', (5,2)),
       
   166     (5,4): ('e', (5,2)),
       
   167     (5,5): ('b', [(2, 2), TE, TE, TE, TE, TE, TE]),
       
   168     (5,6): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   169     (5,7): ('e', (5,0)),
       
   170     (5,8): ('e', (5,0)),
       
   171 
       
   172     # None
       
   173     (6,0): ('b', [TE, TE, TE, TE, TE, TE, TE]),
       
   174     (6,1): ('e', (6,0)),
       
   175     (6,2): ('e', (6,0)),
       
   176     (6,3): ('e', (6,0)),
       
   177     (6,4): ('e', (6,0)),
       
   178     (6,5): ('e', (6,0)),
       
   179     (6,6): ('e', (6,0)),
       
   180     (6,7): ('e', (6,0)),
       
   181     (6,8): ('e', (6,0)),
       
   182 
       
   183     # MethodNumber(2)
       
   184     (7,0): ('e', (0,0)),
       
   185     (7,1): ('e', (0,1)),
       
   186     (7,2): ('e', (0,2)),
       
   187     (7,3): ('e', (0,3)),
       
   188     (7,4): ('e', (0,4)),
       
   189     (7,5): ('e', (0,5)),
       
   190     (7,6): ('e', (0,6)),
       
   191     (7,7): ('e', (0,7)),
       
   192     (7,8): ('e', (0,8)),
       
   193 
       
   194     # CoerceNumber(2)
       
   195     (8,0): ('e', (0,0)),
       
   196     (8,1): ('e', (0,1)),
       
   197     (8,2): ('e', (0,2)),
       
   198     (8,3): ('e', (0,3)),
       
   199     (8,4): ('e', (0,4)),
       
   200     (8,5): ('e', (0,5)),
       
   201     (8,6): ('e', (0,6)),
       
   202     (8,7): ('e', (0,7)),
       
   203     (8,8): ('e', (0,8)),
       
   204 }
       
   205 
       
   206 def process_infix_results():
       
   207     for key in sorted(infix_results):
       
   208         val = infix_results[key]
       
   209         if val[0] == 'e':
       
   210             infix_results[key] = infix_results[val[1]]
       
   211         else:
       
   212             if val[0] == 's':
       
   213                 res = (val[1], val[2])
       
   214             elif val[0] == 'b':
       
   215                 res = (val[1], val[1])
       
   216             for i in range(1):
       
   217                 if isinstance(res[i][6], tuple):
       
   218                     if 1/2 == 0:
       
   219                         # testing with classic (floor) division
       
   220                         res[i][6] = res[i][6][0]
       
   221                     else:
       
   222                         # testing with -Qnew
       
   223                         res[i][6] = res[i][6][1]
       
   224             infix_results[key] = res
       
   225 
       
   226 
       
   227 
       
   228 process_infix_results()
       
   229 # now infix_results has two lists of results for every pairing.
       
   230 
       
   231 prefix_binops = [ 'divmod' ]
       
   232 prefix_results = [
       
   233     [(1,0), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1,0)],
       
   234     [(1L,0L), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1L,0L)],
       
   235     [(2.0,0.0), (2.0,0.0), (1.0,0.0), ((2+0j),0j), TE, TE, TE, TE, (2.0,0.0)],
       
   236     [((1+0j),0j), ((1+0j),0j), (0j,(2+0j)), ((1+0j),0j), TE, TE, TE, TE, ((1+0j),0j)],
       
   237     [TE, TE, TE, TE, TE, TE, TE, TE, TE],
       
   238     [TE, TE, TE, TE, TE, TE, TE, TE, TE],
       
   239     [TE, TE, TE, TE, TE, TE, TE, TE, TE],
       
   240     [TE, TE, TE, TE, TE, TE, TE, TE, TE],
       
   241     [(1,0), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1,0)]
       
   242 ]
       
   243 
       
   244 def format_float(value):
       
   245     if abs(value) < 0.01:
       
   246         return '0.0'
       
   247     else:
       
   248         return '%.1f' % value
       
   249 
       
   250 # avoid testing platform fp quirks
       
   251 def format_result(value):
       
   252     if isinstance(value, complex):
       
   253         return '(%s + %sj)' % (format_float(value.real),
       
   254                                format_float(value.imag))
       
   255     elif isinstance(value, float):
       
   256         return format_float(value)
       
   257     return str(value)
       
   258 
       
   259 class CoercionTest(unittest.TestCase):
       
   260     def test_infix_binops(self):
       
   261         for ia, a in enumerate(candidates):
       
   262             for ib, b in enumerate(candidates):
       
   263                 results = infix_results[(ia, ib)]
       
   264                 for op, res, ires in zip(infix_binops, results[0], results[1]):
       
   265                     if res is TE:
       
   266                         self.assertRaises(TypeError, eval,
       
   267                                           'a %s b' % op, {'a': a, 'b': b})
       
   268                     else:
       
   269                         self.assertEquals(format_result(res),
       
   270                                           format_result(eval('a %s b' % op)),
       
   271                                           '%s %s %s == %s failed' % (a, op, b, res))
       
   272                     try:
       
   273                         z = copy.copy(a)
       
   274                     except copy.Error:
       
   275                         z = a # assume it has no inplace ops
       
   276                     if ires is TE:
       
   277                         try:
       
   278                             exec 'z %s= b' % op
       
   279                         except TypeError:
       
   280                             pass
       
   281                         else:
       
   282                             self.fail("TypeError not raised")
       
   283                     else:
       
   284                         exec('z %s= b' % op)
       
   285                         self.assertEquals(ires, z)
       
   286 
       
   287     def test_prefix_binops(self):
       
   288         for ia, a in enumerate(candidates):
       
   289             for ib, b in enumerate(candidates):
       
   290                 for op in prefix_binops:
       
   291                     res = prefix_results[ia][ib]
       
   292                     if res is TE:
       
   293                         self.assertRaises(TypeError, eval,
       
   294                                           '%s(a, b)' % op, {'a': a, 'b': b})
       
   295                     else:
       
   296                         self.assertEquals(format_result(res),
       
   297                                           format_result(eval('%s(a, b)' % op)),
       
   298                                           '%s(%s, %s) == %s failed' % (op, a, b, res))
       
   299 
       
   300     def test_cmptypes(self):
       
   301         # Built-in tp_compare slots expect their arguments to have the
       
   302         # same type, but a user-defined __coerce__ doesn't have to obey.
       
   303         # SF #980352
       
   304         evil_coercer = CoerceTo(42)
       
   305         # Make sure these don't crash any more
       
   306         self.assertNotEquals(cmp(u'fish', evil_coercer), 0)
       
   307         self.assertNotEquals(cmp(slice(1), evil_coercer), 0)
       
   308         # ...but that this still works
       
   309         class WackyComparer(object):
       
   310             def __cmp__(slf, other):
       
   311                 self.assert_(other == 42, 'expected evil_coercer, got %r' % other)
       
   312                 return 0
       
   313         self.assertEquals(cmp(WackyComparer(), evil_coercer), 0)
       
   314         # ...and classic classes too, since that code path is a little different
       
   315         class ClassicWackyComparer:
       
   316             def __cmp__(slf, other):
       
   317                 self.assert_(other == 42, 'expected evil_coercer, got %r' % other)
       
   318                 return 0
       
   319         self.assertEquals(cmp(ClassicWackyComparer(), evil_coercer), 0)
       
   320 
       
   321     def test_infinite_rec_classic_classes(self):
       
   322         # if __coerce__() returns its arguments reversed it causes an infinite
       
   323         # recursion for classic classes.
       
   324         class Tester:
       
   325             def __coerce__(self, other):
       
   326                 return other, self
       
   327 
       
   328         exc = TestFailed("__coerce__() returning its arguments reverse "
       
   329                                 "should raise RuntimeError")
       
   330         try:
       
   331             Tester() + 1
       
   332         except (RuntimeError, TypeError):
       
   333             return
       
   334         except:
       
   335             raise exc
       
   336         else:
       
   337             raise exc
       
   338 
       
   339 def test_main():
       
   340     warnings.filterwarnings("ignore",
       
   341                             r'complex divmod\(\), // and % are deprecated',
       
   342                             DeprecationWarning,
       
   343                             r'test.test_coercion$')
       
   344     run_unittest(CoercionTest)
       
   345 
       
   346 if __name__ == "__main__":
       
   347     test_main()