[pypy-commit] pypy default: (cfbolz, arigo)
arigo
pypy.commits at gmail.com
Wed Aug 24 10:40:12 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r86500:123020cd1730
Date: 2016-08-24 15:47 +0100
http://bitbucket.org/pypy/pypy/changeset/123020cd1730/
Log: (cfbolz, arigo)
Add a hypothesis-based test for creating and changing attributes on
a class or on an instance (regular attributes, slots, methods, etc.)
diff --git a/pypy/objspace/std/test/test_random_attr.py b/pypy/objspace/std/test/test_random_attr.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_random_attr.py
@@ -0,0 +1,131 @@
+import pytest
+import sys
+from hypothesis import given, strategies, settings
+from pypy.tool.pytest.objspace import gettestobjspace
+
+base_initargs = strategies.sampled_from([
+ ("object", (), False),
+ ("type(sys)", ("fake", ), True),
+ ("NewBase", (), True),
+ ("OldBase", (), False),
+ ("object, OldBase", (), False),
+ ("type(sys), OldBase", ("fake", ), True),
+ ])
+
+attrnames = strategies.sampled_from(["a", "b", "c"])
+
+ at strategies.composite
+def make_code(draw):
+ # now here we can do this kind of thing:
+ baseclass, initargs, hasdict = draw(base_initargs)
+ # and with arbitrary strategies
+
+ def class_attr():
+ what = draw(strategies.sampled_from(["value", "method", "property"]))
+ if what == "value":
+ val = draw(strategies.integers())
+ return val, str(val)
+ if what == "method":
+ val = draw(strategies.integers())
+ return (lambda self, val=val: val,
+ "lambda self: %d" % val)
+ if what == "property":
+ val = draw(strategies.integers())
+ return (property(lambda self, val=val: val,
+ lambda self, val: None,
+ lambda self: None),
+ "property(lambda self: %d, lambda self, val: None, lambda self: None)" % val)
+
+ code = ["import sys", "class OldBase:pass", "class NewBase(object):pass", "class A(%s):" % baseclass]
+ dct = {}
+ if draw(strategies.booleans()):
+ slots = draw(strategies.lists(attrnames))
+ if not hasdict and draw(strategies.booleans()):
+ slots.append("__dict__")
+ dct["__slots__"] = slots
+ code.append(" __slots__ = %s" % (slots, ))
+ for name in ["a", "b", "c"]:
+ if not draw(strategies.booleans()):
+ continue
+ dct[name], codeval = class_attr()
+ code.append(" %s = %s" % (name, codeval))
+ class OldBase: pass
+ class NewBase(object): pass
+ evaldct = {'OldBase': OldBase, 'NewBase': NewBase}
+ if baseclass == 'OldBase':
+ metaclass = type(OldBase)
+ else:
+ metaclass = type
+ cls = metaclass("A", eval(baseclass+',', globals(), evaldct), dct)
+ inst = cls(*initargs)
+ code.append(" pass")
+ code.append("a = A(*%s)" % (initargs, ))
+ for attr in draw(strategies.lists(attrnames, min_size=1)):
+ op = draw(strategies.sampled_from(["read", "read", "read",
+ "write", "writemeth", "writeclass", "writebase",
+ "del", "delclass"]))
+ if op == "read":
+ try:
+ res = getattr(inst, attr)
+ except AttributeError:
+ code.append("raises(AttributeError, 'a.%s')" % (attr, ))
+ else:
+ if callable(res):
+ code.append("assert a.%s() == %s" % (attr, res()))
+ else:
+ code.append("assert a.%s == %s" % (attr, res))
+ elif op == "write":
+ val = draw(strategies.integers())
+ try:
+ setattr(inst, attr, val)
+ except AttributeError:
+ code.append("raises(AttributeError, 'a.%s=%s')" % (attr, val))
+ else:
+ code.append("a.%s = %s" % (attr, val))
+ elif op == "writemeth":
+ val = draw(strategies.integers())
+ try:
+ setattr(inst, attr, lambda val=val: val)
+ except AttributeError:
+ code.append("raises(AttributeError, 'a.%s=0')" % (attr, ))
+ else:
+ code.append("a.%s = lambda : %s" % (attr, val))
+ elif op == "writeclass":
+ val, codeval = class_attr()
+ setattr(cls, attr, val)
+ code.append("A.%s = %s" % (attr, codeval))
+ elif op == "writebase":
+ val, codeval = class_attr()
+ setattr(OldBase, attr, val)
+ setattr(NewBase, attr, val)
+ code.append("OldBase.%s = NewBase.%s = %s" % (attr, attr , codeval))
+ elif op == "del":
+ try:
+ delattr(inst, attr)
+ except AttributeError:
+ code.append("raises(AttributeError, 'del a.%s')" % (attr, ))
+ else:
+ code.append("del a.%s" % (attr, ))
+ elif op == "delclass":
+ try:
+ delattr(cls, attr)
+ except AttributeError:
+ code.append("raises(AttributeError, 'del A.%s')" % (attr, ))
+ else:
+ code.append("del A.%s" % (attr, ))
+ return "\n ".join(code)
+
+
+ at given(make_code())
+#@settings(max_examples=5000)
+def test_random_attrs(code):
+ try:
+ import __pypy__
+ except ImportError:
+ pass
+ else:
+ pytest.skip("makes no sense under pypy!")
+ space = gettestobjspace()
+ print code
+ exec "if 1:\n " + code
+ space.appexec([], "():\n " + code)
More information about the pypy-commit
mailing list