1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
# test about the binop operation rule, see issue 412
from pypy.conftest import option
class AppTestBinopCombinations:
def setup_class(cls):
w_helpers = cls.space.appexec([], """():
class Base(object):
def __init__(self, name):
self.name = name
def lookup_where(obj, name):
mro = type(obj).__mro__
for t in mro:
if name in t.__dict__:
return t.__dict__[name], t
return None, None
def refop(x, y, opname, ropname):
# this has been validated by running the tests on top of cpython
# so for the space of possibilities that the tests touch it is known
# to behave like cpython as long as the latter doesn't change its own
# algorithm
t1 = type(x)
t2 = type(y)
op, where1 = lookup_where(x, opname)
rop, where2 = lookup_where(y, ropname)
if op is None and rop is not None:
return rop(y, x)
if rop and where1 is not where2:
if (issubclass(t2, t1) and not issubclass(where1, where2)
and not issubclass(t1, where2)
):
return rop(y, x)
if op is None:
return "TypeError"
return op(x,y)
def do_test(X, Y, name, impl):
x = X('x')
y = Y('y')
opname = '__%s__' % name
ropname = '__r%s__' % name
count = [0]
fail = []
def check(z1, z2):
ref = refop(z1, z2, opname, ropname)
try:
v = impl(z1, z2)
except TypeError:
v = "TypeError"
if v != ref:
fail.append(count[0])
def override_in_hier(n=6):
if n == 0:
count[0] += 1
check(x, y)
check(y, x)
return
f = lambda self, other: (n, self.name, other.name)
if n%2 == 0:
name = opname
else:
name = ropname
for C in Y.__mro__:
if name in C.__dict__:
continue
if C is not object:
setattr(C, name, f)
override_in_hier(n-1)
if C is not object:
delattr(C, name)
override_in_hier()
#print count[0]
return fail
return Base, do_test
""")
cls.w_helpers = w_helpers
cls.w_appdirect = cls.space.wrap(option.runappdirect)
def test_overriding_base_binop_explict(self):
class MulBase(object):
def __init__(self, value):
self.value = value
def __mul__(self, other):
return self.value * other.value
def __rmul__(self, other):
return other.value * self.value
class DoublerBase(MulBase):
def __mul__(self, other):
return 2 * (self.value * other.value)
class AnotherDoubler(DoublerBase):
pass
res = DoublerBase(2) * AnotherDoubler(3)
assert res == 12
def test_binop_combinations_mul(self):
if not self.appdirect:
skip("slow test, should be run as appdirect test")
Base, do_test = self.helpers
class X(Base):
pass
class Y(X):
pass
fail = do_test(X, Y, 'mul', lambda x,y: x*y)
#print len(fail)
assert not fail
def test_binop_combinations_sub(self):
Base, do_test = self.helpers
class X(Base):
pass
class Y(X):
pass
fail = do_test(X, Y, 'sub', lambda x,y: x-y)
#print len(fail)
assert not fail
def test_binop_combinations_pow(self):
if not self.appdirect:
skip("slow test, should be run as appdirect test")
Base, do_test = self.helpers
class X(Base):
pass
class Y(X):
pass
fail = do_test(X, Y, 'pow', lambda x,y: x**y)
#print len(fail)
assert not fail
def test_binop_combinations_more_exhaustive(self):
if not self.appdirect:
skip("very slow test, should be run as appdirect test")
Base, do_test = self.helpers
class X(Base):
pass
class B1(object):
pass
class B2(object):
pass
class X1(B1, X, B2):
pass
class C1(object):
pass
class C2(object):
pass
class Y(C1, X1, C2):
pass
fail = do_test(X, Y, 'sub', lambda x,y: x-y)
#print len(fail)
assert not fail
|