#! /usr/bin/python
from twisted.trial import unittest
import schema
class Dummy:
pass
HEADER = 64
INTSIZE = HEADER+1
STR10 = HEADER+1+10
class ConformTest(unittest.TestCase):
"""This tests how Constraints are asserted on outbound objects (where the
object already exists). Inbound constraints are checked in
test_banana.InboundByteStream in the various testConstrainedFoo methods.
"""
def conforms(self, c, obj):
c.checkObject(obj)
def violates(self, c, obj):
self.assertRaises(schema.Violation, c.checkObject, obj)
def assertSize(self, c, maxsize):
return
self.assertEquals(c.maxSize(), maxsize)
def assertDepth(self, c, maxdepth):
self.assertEquals(c.maxDepth(), maxdepth)
def assertUnboundedSize(self, c):
self.assertRaises(schema.UnboundedSchema, c.maxSize)
def assertUnboundedDepth(self, c):
self.assertRaises(schema.UnboundedSchema, c.maxDepth)
def testAny(self):
c = schema.Constraint()
self.assertUnboundedSize(c)
self.assertUnboundedDepth(c)
def testInteger(self):
# s_int32_t
c = schema.IntegerConstraint()
self.assertSize(c, INTSIZE)
self.assertDepth(c, 1)
self.conforms(c, 123)
self.violates(c, 2**64)
self.conforms(c, 0)
self.conforms(c, 2**31-1)
self.violates(c, 2**31)
self.conforms(c, -2**31)
self.violates(c, -2**31-1)
self.violates(c, "123")
self.violates(c, Dummy())
self.violates(c, None)
def testLargeInteger(self):
c = schema.IntegerConstraint(64)
self.assertSize(c, INTSIZE+64)
self.assertDepth(c, 1)
self.conforms(c, 123)
self.violates(c, "123")
self.violates(c, None)
self.conforms(c, 2**512-1)
self.violates(c, 2**512)
self.conforms(c, -2**512+1)
self.violates(c, -2**512)
def testString(self):
c = schema.StringConstraint(10)
self.assertSize(c, STR10)
self.assertSize(c, STR10) # twice to test seen=[] logic
self.assertDepth(c, 1)
self.conforms(c, "I'm short")
self.violates(c, "I am too long")
self.conforms(c, "a" * 10)
self.violates(c, "a" * 11)
self.violates(c, 123)
self.violates(c, Dummy())
self.violates(c, None)
def testBool(self):
c = schema.BooleanConstraint()
self.assertSize(c, 147)
self.assertDepth(c, 2)
self.conforms(c, False)
self.conforms(c, True)
self.violates(c, 0)
self.violates(c, 1)
self.violates(c, "vrai")
self.violates(c, Dummy())
self.violates(c, None)
def testPoly(self):
c = schema.PolyConstraint(schema.StringConstraint(100),
schema.IntegerConstraint())
self.assertSize(c, 165)
self.assertDepth(c, 1)
def testTuple(self):
c = schema.TupleConstraint(schema.StringConstraint(10),
schema.StringConstraint(100),
schema.IntegerConstraint() )
self.conforms(c, ("hi", "there buddy, you're number", 1))
self.violates(c, "nope")
self.violates(c, ("string", "string", "NaN"))
self.violates(c, ("string that is too long", "string", 1))
self.violates(c, ["Are tuples", "and lists the same?", 0])
self.assertSize(c, 72+75+165+73)
self.assertDepth(c, 2)
def testNestedTuple(self):
inner = schema.TupleConstraint(schema.StringConstraint(10),
schema.IntegerConstraint())
self.assertSize(inner, 72+75+73)
self.assertDepth(inner, 2)
outer = schema.TupleConstraint(schema.StringConstraint(100),
inner)
self.assertSize(outer, 72+165 + 72+75+73)
self.assertDepth(outer, 3)
self.conforms(inner, ("hi", 2))
self.conforms(outer, ("long string here", ("short", 3)))
self.violates(outer, (("long string here", ("short", 3, "extra"))))
self.violates(outer, (("long string here", ("too long string", 3))))
outer2 = schema.TupleConstraint(inner, inner)
self.assertSize(outer2, 72+ 2*(72+75+73))
self.assertDepth(outer2, 3)
self.conforms(outer2, (("hi", 1), ("there", 2)) )
self.violates(outer2, ("hi", 1, "flat", 2) )
def testUnbounded(self):
big = schema.StringConstraint(None)
self.assertUnboundedSize(big)
self.assertDepth(big, 1)
self.conforms(big, "blah blah blah blah blah" * 1024)
self.violates(big, 123)
bag = schema.TupleConstraint(schema.IntegerConstraint(),
big)
self.assertUnboundedSize(bag)
self.assertDepth(bag, 2)
polybag = schema.PolyConstraint(schema.IntegerConstraint(),
bag)
self.assertUnboundedSize(polybag)
self.assertDepth(polybag, 2)
def testRecursion(self):
# we have to fiddle with PolyConstraint's innards
value = schema.ChoiceOf(schema.StringConstraint(),
schema.IntegerConstraint(),
# will add 'value' here
)
self.assertSize(value, 1065)
self.assertDepth(value, 1)
self.conforms(value, "key")
self.conforms(value, 123)
self.violates(value, [])
mapping = schema.TupleConstraint(schema.StringConstraint(10),
value)
self.assertSize(mapping, 72+75+1065)
self.assertDepth(mapping, 2)
self.conforms(mapping, ("name", "key"))
self.conforms(mapping, ("name", 123))
value.alternatives = value.alternatives + (mapping,)
self.assertUnboundedSize(value)
self.assertUnboundedDepth(value)
self.assertUnboundedSize(mapping)
self.assertUnboundedDepth(mapping)
# but note that the constraint can still be applied
self.conforms(mapping, ("name", 123))
self.conforms(mapping, ("name", "key"))
self.conforms(mapping, ("name", ("key", "value")))
self.conforms(mapping, ("name", ("key", 123)))
self.violates(mapping, ("name", ("key", [])))
l = []
l.append(l)
self.violates(mapping, ("name", l))
def testList(self):
l = schema.ListOf(schema.StringConstraint(10))
self.assertSize(l, 71 + 30*75)
self.assertDepth(l, 2)
self.conforms(l, ["one", "two", "three"])
self.violates(l, ("can't", "fool", "me"))
self.violates(l, ["but", "perspicacity", "is too long"])
self.conforms(l, ["short", "sweet"])
l2 = schema.ListOf(schema.StringConstraint(10), 3)
self.assertSize(l2, 71 + 3*75)
self.assertDepth(l2, 2)
self.conforms(l2, ["the number", "shall be", "three"])
self.violates(l2, ["five", "is", "...", "right", "out"])
def testDict(self):
d = schema.DictOf(schema.StringConstraint(10),
schema.IntegerConstraint(),
maxKeys=4)
self.assertDepth(d, 2)
self.conforms(d, {"a": 1, "b": 2})
self.conforms(d, {"foo": 123, "bar": 345, "blah": 456, "yar": 789})
self.violates(d, None)
self.violates(d, 12)
self.violates(d, ["nope"])
self.violates(d, ("nice", "try"))
self.violates(d, {1:2, 3:4})
self.violates(d, {"a": "b"})
self.violates(d, {"a": 1, "b": 2, "c": 3, "d": 4, "toomuch": 5})
def testAttrDict(self):
d = schema.AttributeDictConstraint(('a', int), ('b', str))
self.conforms(d, {"a": 1, "b": "string"})
self.violates(d, {"a": 1, "b": 2})
self.violates(d, {"a": 1, "b": "string", "c": "is a crowd"})
d = schema.AttributeDictConstraint(('a', int), ('b', str),
ignoreUnknown=True)
self.conforms(d, {"a": 1, "b": "string"})
self.violates(d, {"a": 1, "b": 2})
self.conforms(d, {"a": 1, "b": "string", "c": "is a crowd"})
d = schema.AttributeDictConstraint(attributes={"a": int, "b": str})
self.conforms(d, {"a": 1, "b": "string"})
self.violates(d, {"a": 1, "b": 2})
self.violates(d, {"a": 1, "b": "string", "c": "is a crowd"})
class CreateTest(unittest.TestCase):
def check(self, obj, expected):
self.failUnless(isinstance(obj, expected))
def testMakeConstraint(self):
make = schema.makeConstraint
c = make(int)
self.check(c, schema.IntegerConstraint)
self.failUnlessEqual(c.maxBytes, -1)
c = make(str)
self.check(c, schema.StringConstraint)
self.failUnlessEqual(c.maxLength, 1000)
self.check(make(bool), schema.BooleanConstraint)
self.check(make(float), schema.NumberConstraint)
self.check(make(schema.NumberConstraint()), schema.NumberConstraint)
c = make((int, str))
self.check(c, schema.PolyConstraint)
self.failUnlessEqual(len(c.alternatives), 2)
self.check(c.alternatives[0], schema.IntegerConstraint)
self.check(c.alternatives[1], schema.StringConstraint)
syntax highlighted by Code2HTML, v. 0.9.1