mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Make test_coercion pass with -Qnew. Converted to unittest on the occasion.
This commit is contained in:
		
							parent
							
								
									4054b9720b
								
							
						
					
					
						commit
						686eaeb0b8
					
				
					 2 changed files with 240 additions and 1134 deletions
				
			
		|  | @ -1,6 +1,8 @@ | |||
| import copy | ||||
| import sys | ||||
| import warnings | ||||
| import unittest | ||||
| from test.test_support import run_unittest | ||||
| 
 | ||||
| # Fake a number that implements numeric methods through __coerce__ | ||||
| class CoerceNumber: | ||||
|  | @ -16,10 +18,19 @@ def __coerce__(self, other): | |||
|         else: | ||||
|             return (self.arg, other) | ||||
| 
 | ||||
| # New-style class version of CoerceNumber | ||||
| class CoerceTo(object): | ||||
|     def __init__(self, arg): | ||||
|         self.arg = arg | ||||
|     def __coerce__(self, other): | ||||
|         if isinstance(other, CoerceTo): | ||||
|             return self.arg, other.arg | ||||
|         else: | ||||
|             return self.arg, other | ||||
| 
 | ||||
| 
 | ||||
| # Fake a number that implements numeric ops through methods. | ||||
| class MethodNumber: | ||||
| 
 | ||||
|     def __init__(self,arg): | ||||
|         self.arg = arg | ||||
| 
 | ||||
|  | @ -50,6 +61,18 @@ def __div__(self,other): | |||
|     def __rdiv__(self,other): | ||||
|         return other / self.arg | ||||
| 
 | ||||
|     def __truediv__(self,other): | ||||
|         return self.arg / other | ||||
| 
 | ||||
|     def __rtruediv__(self,other): | ||||
|         return other / self.arg | ||||
| 
 | ||||
|     def __floordiv__(self,other): | ||||
|         return self.arg // other | ||||
| 
 | ||||
|     def __rfloordiv__(self,other): | ||||
|         return other // self.arg | ||||
| 
 | ||||
|     def __pow__(self,other): | ||||
|         return self.arg ** other | ||||
| 
 | ||||
|  | @ -66,11 +89,157 @@ def __cmp__(self, other): | |||
|         return cmp(self.arg, other) | ||||
| 
 | ||||
| 
 | ||||
| candidates = [ 2, 4.0, 2L, 2+0j, [1], (2,), None, | ||||
|                MethodNumber(2), CoerceNumber(2)] | ||||
| candidates = [2, 2L, 4.0, 2+0j, [1], (2,), None, | ||||
|               MethodNumber(2), CoerceNumber(2)] | ||||
| 
 | ||||
| infix_binops = [ '+', '-', '*', '**', '%', '//', '/' ] | ||||
| 
 | ||||
| TE = TypeError | ||||
| # b = both normal and augmented give same result list | ||||
| # s = single result lists for normal and augmented | ||||
| # e = equals other results | ||||
| # result lists: ['+', '-', '*', '**', '%', '//', ('classic /', 'new /')] | ||||
| #                                                ^^^^^^^^^^^^^^^^^^^^^^ | ||||
| #                                               2-tuple if results differ | ||||
| #                                                 else only one value | ||||
| infix_results = { | ||||
|     # 2 | ||||
|     (0,0): ('b', [4, 0, 4, 4, 0, 1, (1, 1.0)]), | ||||
|     (0,1): ('e', (0,0)), | ||||
|     (0,2): ('b', [6.0, -2.0, 8.0, 16.0, 2.0, 0.0, 0.5]), | ||||
|     (0,3): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]), | ||||
|     (0,4): ('b', [TE, TE, [1, 1], TE, TE, TE, TE]), | ||||
|     (0,5): ('b', [TE, TE, (2, 2), TE, TE, TE, TE]), | ||||
|     (0,6): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (0,7): ('e', (0,0)), | ||||
|     (0,8): ('e', (0,0)), | ||||
| 
 | ||||
|     # 2L | ||||
|     (1,0): ('e', (0,0)), | ||||
|     (1,1): ('e', (0,1)), | ||||
|     (1,2): ('e', (0,2)), | ||||
|     (1,3): ('e', (0,3)), | ||||
|     (1,4): ('e', (0,4)), | ||||
|     (1,5): ('e', (0,5)), | ||||
|     (1,6): ('e', (0,6)), | ||||
|     (1,7): ('e', (0,7)), | ||||
|     (1,8): ('e', (0,8)), | ||||
| 
 | ||||
|     # 4.0 | ||||
|     (2,0): ('b', [6.0, 2.0, 8.0, 16.0, 0.0, 2.0, 2.0]), | ||||
|     (2,1): ('e', (2,0)), | ||||
|     (2,2): ('b', [8.0, 0.0, 16.0, 256.0, 0.0, 1.0, 1.0]), | ||||
|     (2,3): ('b', [6+0j, 2+0j, 8+0j, 16+0j, 0+0j, 2+0j, 2+0j]), | ||||
|     (2,4): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (2,5): ('e', (2,4)), | ||||
|     (2,6): ('e', (2,4)), | ||||
|     (2,7): ('e', (2,0)), | ||||
|     (2,8): ('e', (2,0)), | ||||
| 
 | ||||
|     # (2+0j) | ||||
|     (3,0): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]), | ||||
|     (3,1): ('e', (3,0)), | ||||
|     (3,2): ('b', [6+0j, -2+0j, 8+0j, 16+0j, 2+0j, 0+0j, 0.5+0j]), | ||||
|     (3,3): ('b', [4+0j, 0+0j, 4+0j, 4+0j, 0+0j, 1+0j, 1+0j]), | ||||
|     (3,4): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (3,5): ('e', (3,4)), | ||||
|     (3,6): ('e', (3,4)), | ||||
|     (3,7): ('e', (3,0)), | ||||
|     (3,8): ('e', (3,0)), | ||||
| 
 | ||||
|     # [1] | ||||
|     (4,0): ('b', [TE, TE, [1, 1], TE, TE, TE, TE]), | ||||
|     (4,1): ('e', (4,0)), | ||||
|     (4,2): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (4,3): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (4,4): ('b', [[1, 1], TE, TE, TE, TE, TE, TE]), | ||||
|     (4,5): ('s', [TE, TE, TE, TE, TE, TE, TE], [[1, 2], TE, TE, TE, TE, TE, TE]), | ||||
|     (4,6): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (4,7): ('e', (4,0)), | ||||
|     (4,8): ('e', (4,0)), | ||||
| 
 | ||||
|     # (2,) | ||||
|     (5,0): ('b', [TE, TE, (2, 2), TE, TE, TE, TE]), | ||||
|     (5,1): ('e', (5,0)), | ||||
|     (5,2): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (5,3): ('e', (5,2)), | ||||
|     (5,4): ('e', (5,2)), | ||||
|     (5,5): ('b', [(2, 2), TE, TE, TE, TE, TE, TE]), | ||||
|     (5,6): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (5,7): ('e', (5,0)), | ||||
|     (5,8): ('e', (5,0)), | ||||
| 
 | ||||
|     # None | ||||
|     (6,0): ('b', [TE, TE, TE, TE, TE, TE, TE]), | ||||
|     (6,1): ('e', (6,0)), | ||||
|     (6,2): ('e', (6,0)), | ||||
|     (6,3): ('e', (6,0)), | ||||
|     (6,4): ('e', (6,0)), | ||||
|     (6,5): ('e', (6,0)), | ||||
|     (6,6): ('e', (6,0)), | ||||
|     (6,7): ('e', (6,0)), | ||||
|     (6,8): ('e', (6,0)), | ||||
| 
 | ||||
|     # MethodNumber(2) | ||||
|     (7,0): ('e', (0,0)),  | ||||
|     (7,1): ('e', (0,1)), | ||||
|     (7,2): ('e', (0,2)), | ||||
|     (7,3): ('e', (0,3)), | ||||
|     (7,4): ('e', (0,4)), | ||||
|     (7,5): ('e', (0,5)), | ||||
|     (7,6): ('e', (0,6)), | ||||
|     (7,7): ('e', (0,7)), | ||||
|     (7,8): ('e', (0,8)), | ||||
| 
 | ||||
|     # CoerceNumber(2) | ||||
|     (8,0): ('e', (0,0)),  | ||||
|     (8,1): ('e', (0,1)), | ||||
|     (8,2): ('e', (0,2)), | ||||
|     (8,3): ('e', (0,3)), | ||||
|     (8,4): ('e', (0,4)), | ||||
|     (8,5): ('e', (0,5)), | ||||
|     (8,6): ('e', (0,6)), | ||||
|     (8,7): ('e', (0,7)), | ||||
|     (8,8): ('e', (0,8)), | ||||
| } | ||||
| 
 | ||||
| def process_infix_results(): | ||||
|     for key in sorted(infix_results): | ||||
|         val = infix_results[key] | ||||
|         if val[0] == 'e': | ||||
|             infix_results[key] = infix_results[val[1]] | ||||
|         else: | ||||
|             if val[0] == 's': | ||||
|                 res = (val[1], val[2]) | ||||
|             elif val[0] == 'b': | ||||
|                 res = (val[1], val[1]) | ||||
|             for i in range(1): | ||||
|                 if isinstance(res[i][6], tuple): | ||||
|                     if 1/2 == 0: | ||||
|                         # testing with classic (floor) division | ||||
|                         res[i][6] = res[i][6][0] | ||||
|                     else: | ||||
|                         # testing with -Qnew | ||||
|                         res[i][6] = res[i][6][1] | ||||
|             infix_results[key] = res | ||||
| 
 | ||||
|          | ||||
|          | ||||
| process_infix_results() | ||||
| # now infix_results has two lists of results for every pairing. | ||||
| 
 | ||||
| infix_binops = [ '+', '-', '*', '/', '**', '%' ] | ||||
| prefix_binops = [ 'divmod' ] | ||||
| prefix_results = [ | ||||
|     [(1,0), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1,0)], | ||||
|     [(1L,0L), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1L,0L)], | ||||
|     [(2.0,0.0), (2.0,0.0), (1.0,0.0), ((2+0j),0j), TE, TE, TE, TE, (2.0,0.0)], | ||||
|     [((1+0j),0j), ((1+0j),0j), (0j,(2+0j)), ((1+0j),0j), TE, TE, TE, TE, ((1+0j),0j)], | ||||
|     [TE, TE, TE, TE, TE, TE, TE, TE, TE], | ||||
|     [TE, TE, TE, TE, TE, TE, TE, TE, TE], | ||||
|     [TE, TE, TE, TE, TE, TE, TE, TE, TE], | ||||
|     [TE, TE, TE, TE, TE, TE, TE, TE, TE], | ||||
|     [(1,0), (1L,0L), (0.0,2.0), ((1+0j),0j), TE, TE, TE, TE, (1,0)] | ||||
| ] | ||||
| 
 | ||||
| def format_float(value): | ||||
|     if abs(value) < 0.01: | ||||
|  | @ -87,83 +256,74 @@ def format_result(value): | |||
|         return format_float(value) | ||||
|     return str(value) | ||||
| 
 | ||||
| def do_infix_binops(): | ||||
|     for a in candidates: | ||||
|         for b in candidates: | ||||
|             for op in infix_binops: | ||||
|                 print '%s %s %s' % (a, op, b), | ||||
|                 try: | ||||
|                     x = eval('a %s b' % op) | ||||
|                 except: | ||||
|                     error = sys.exc_info()[:2] | ||||
|                     print '... %s.%s' % (error[0].__module__, error[0].__name__) | ||||
|                 else: | ||||
|                     print '=', format_result(x) | ||||
|                 try: | ||||
|                     z = copy.copy(a) | ||||
|                 except copy.Error: | ||||
|                     z = a # assume it has no inplace ops | ||||
|                 print '%s %s= %s' % (a, op, b), | ||||
|                 try: | ||||
|                     exec('z %s= b' % op) | ||||
|                 except: | ||||
|                     error = sys.exc_info()[:2] | ||||
|                     print '... %s.%s' % (error[0].__module__, error[0].__name__) | ||||
|                 else: | ||||
|                     print '=>', format_result(z) | ||||
| class CoercionTest(unittest.TestCase): | ||||
|     def test_infix_binops(self): | ||||
|         for ia, a in enumerate(candidates): | ||||
|             for ib, b in enumerate(candidates): | ||||
|                 results = infix_results[(ia, ib)] | ||||
|                 for op, res, ires in zip(infix_binops, results[0], results[1]): | ||||
|                     if res is TE: | ||||
|                         self.assertRaises(TypeError, eval, | ||||
|                                           'a %s b' % op, {'a': a, 'b': b}) | ||||
|                     else: | ||||
|                         self.assertEquals(format_result(res), | ||||
|                                           format_result(eval('a %s b' % op)), | ||||
|                                           '%s %s %s == %s failed' % (a, op, b, res)) | ||||
|                     try: | ||||
|                         z = copy.copy(a) | ||||
|                     except copy.Error: | ||||
|                         z = a # assume it has no inplace ops | ||||
|                     if ires is TE: | ||||
|                         try: | ||||
|                             exec 'z %s= b' % op | ||||
|                         except TypeError: | ||||
|                             pass | ||||
|                         else: | ||||
|                             self.fail("TypeError not raised") | ||||
|                     else: | ||||
|                         exec('z %s= b' % op) | ||||
|                         self.assertEquals(ires, z) | ||||
| 
 | ||||
| def do_prefix_binops(): | ||||
|     for a in candidates: | ||||
|         for b in candidates: | ||||
|             for op in prefix_binops: | ||||
|                 print '%s(%s, %s)' % (op, a, b), | ||||
|                 try: | ||||
|                     x = eval('%s(a, b)' % op) | ||||
|                 except: | ||||
|                     error = sys.exc_info()[:2] | ||||
|                     print '... %s.%s' % (error[0].__module__, error[0].__name__) | ||||
|                 else: | ||||
|                     print '=', format_result(x) | ||||
|     def test_prefix_binops(self): | ||||
|         for ia, a in enumerate(candidates): | ||||
|             for ib, b in enumerate(candidates): | ||||
|                 for op in prefix_binops: | ||||
|                     res = prefix_results[ia][ib] | ||||
|                     if res is TE: | ||||
|                         self.assertRaises(TypeError, eval, | ||||
|                                           '%s(a, b)' % op, {'a': a, 'b': b}) | ||||
|                     else: | ||||
|                         self.assertEquals(format_result(res), | ||||
|                                           format_result(eval('%s(a, b)' % op)), | ||||
|                                           '%s(%s, %s) == %s failed' % (op, a, b, res)) | ||||
| 
 | ||||
| # New-style class version of CoerceNumber | ||||
| class CoerceTo(object): | ||||
|     def __init__(self, arg): | ||||
|         self.arg = arg | ||||
|     def __coerce__(self, other): | ||||
|         if isinstance(other, CoerceTo): | ||||
|             return self.arg, other.arg | ||||
|         else: | ||||
|             return self.arg, other | ||||
|     def test_cmptypes(self): | ||||
|         # Built-in tp_compare slots expect their arguments to have the | ||||
|         # same type, but a user-defined __coerce__ doesn't have to obey. | ||||
|         # SF #980352 | ||||
|         evil_coercer = CoerceTo(42) | ||||
|         # Make sure these don't crash any more | ||||
|         self.assertNotEquals(cmp(u'fish', evil_coercer), 0) | ||||
|         self.assertNotEquals(cmp(slice(1), evil_coercer), 0) | ||||
|         # ...but that this still works | ||||
|         class WackyComparer(object): | ||||
|             def __cmp__(slf, other): | ||||
|                 self.assert_(other == 42, 'expected evil_coercer, got %r' % other) | ||||
|                 return 0 | ||||
|         self.assertEquals(cmp(WackyComparer(), evil_coercer), 0) | ||||
|         # ...and classic classes too, since that code path is a little different | ||||
|         class ClassicWackyComparer: | ||||
|             def __cmp__(slf, other): | ||||
|                 self.assert_(other == 42, 'expected evil_coercer, got %r' % other) | ||||
|                 return 0 | ||||
|         self.assertEquals(cmp(ClassicWackyComparer(), evil_coercer), 0) | ||||
| 
 | ||||
| def assert_(expr, msg=None): | ||||
|     if not expr: | ||||
|         raise AssertionError, msg | ||||
| def test_main(): | ||||
|     warnings.filterwarnings("ignore", | ||||
|                             r'complex divmod\(\), // and % are deprecated', | ||||
|                             DeprecationWarning, | ||||
|                             r'test.test_coercion$') | ||||
|     run_unittest(CoercionTest) | ||||
| 
 | ||||
| def do_cmptypes(): | ||||
|     # Built-in tp_compare slots expect their arguments to have the | ||||
|     # same type, but a user-defined __coerce__ doesn't have to obey. | ||||
|     # SF #980352 | ||||
|     evil_coercer = CoerceTo(42) | ||||
|     # Make sure these don't crash any more | ||||
|     assert_(cmp(u'fish', evil_coercer) != 0) | ||||
|     assert_(cmp(slice(1), evil_coercer) != 0) | ||||
|     # ...but that this still works | ||||
|     class WackyComparer(object): | ||||
|         def __cmp__(self, other): | ||||
|             assert_(other == 42, 'expected evil_coercer, got %r' % other) | ||||
|             return 0 | ||||
|     assert_(cmp(WackyComparer(), evil_coercer) == 0) | ||||
|     # ...and classic classes too, since that code path is a little different | ||||
|     class ClassicWackyComparer: | ||||
|         def __cmp__(self, other): | ||||
|             assert_(other == 42, 'expected evil_coercer, got %r' % other) | ||||
|             return 0 | ||||
|     assert_(cmp(ClassicWackyComparer(), evil_coercer) == 0) | ||||
| 
 | ||||
| warnings.filterwarnings("ignore", | ||||
|                         r'complex divmod\(\), // and % are deprecated', | ||||
|                         DeprecationWarning, | ||||
|                         r'test.test_coercion$') | ||||
| do_infix_binops() | ||||
| do_prefix_binops() | ||||
| do_cmptypes() | ||||
| if __name__ == "__main__": | ||||
|     test_main() | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Georg Brandl
						Georg Brandl