Skip to content

Latest commit

 

History

History
204 lines (170 loc) · 5.95 KB

tests.rst

File metadata and controls

204 lines (170 loc) · 5.95 KB

Error reporting should be accurate:

>>> from voluptuous import *
>>> schema = Schema(['one', {'two': 'three', 'four': ['five'],
...                          'six': {'seven': 'eight'}}])
>>> schema(['one'])
['one']
>>> schema([{'two': 'three'}])
[{'two': 'three'}]

It should show the exact index and container type, in this case a list value:

>>> schema(['one', 'two'])
Traceback (most recent call last):
...
MultipleInvalid: invalid list value @ data[1]

It should also be accurate for nested values:

>>> schema([{'two': 'nine'}])
Traceback (most recent call last):
...
MultipleInvalid: not a valid value for dictionary value @ data[0]['two']
>>> schema([{'four': ['nine']}])
Traceback (most recent call last):
...
MultipleInvalid: invalid list value @ data[0]['four'][0]
>>> schema([{'six': {'seven': 'nine'}}])
Traceback (most recent call last):
...
MultipleInvalid: not a valid value for dictionary value @ data[0]['six']['seven']

Errors should be reported depth-first:

>>> validate = Schema({'one': {'two': 'three', 'four': 'five'}})
>>> try:
...   validate({'one': {'four': 'six'}})
... except Invalid as e:
...   print(e)
...   print(e.path)
not a valid value for dictionary value @ data['one']['four']
['one', 'four']

Voluptuous supports validation when extra fields are present in the data:

>>> schema = Schema({'one': 1, Extra: object})
>>> schema({'two': 'two', 'one': 1})
{'two': 'two', 'one': 1}
>>> schema = Schema({'one': 1})
>>> schema({'two': 2})
Traceback (most recent call last):
...
MultipleInvalid: extra keys not allowed @ data['two']

dict, list, and tuple should be available as type validators:

>>> Schema(dict)({'a': 1, 'b': 2})
{'a': 1, 'b': 2}
>>> Schema(list)([1,2,3])
[1, 2, 3]
>>> Schema(tuple)((1,2,3))
(1, 2, 3)

Validation should return instances of the right types when the types are subclasses of dict or list:

>>> class Dict(dict):
...   pass
>>>
>>> d = Schema(dict)(Dict(a=1, b=2))
>>> d
{'a': 1, 'b': 2}
>>> type(d) is Dict
True
>>> class List(list):
...   pass
>>>
>>> l = Schema(list)(List([1,2,3]))
>>> l
[1, 2, 3]
>>> type(l) is List
True

Multiple errors are reported:

>>> schema = Schema({'one': 1, 'two': 2})
>>> try:
...   schema({'one': 2, 'two': 3, 'three': 4})
... except MultipleInvalid as e:
...   errors = sorted(e.errors, key=lambda k: str(k))
...   print([str(i) for i in errors])  # doctest: +NORMALIZE_WHITESPACE
["extra keys not allowed @ data['three']",
 "not a valid value for dictionary value @ data['one']",
 "not a valid value for dictionary value @ data['two']"]
>>> schema = Schema([[1], [2], [3]])
>>> try:
...   schema([1, 2, 3])
... except MultipleInvalid as e:
...   print([str(i) for i in e.errors])  # doctest: +NORMALIZE_WHITESPACE
['invalid list value @ data[0]',
 'invalid list value @ data[1]',
 'invalid list value @ data[2]']

Custom classes validate as schemas:

>>> class Thing(object):
...     pass
>>> schema = Schema(Thing)
>>> t = schema(Thing())
>>> type(t) is Thing
True

Classes with custom metaclasses should validate as schemas:

>>> class MyMeta(type):
...     pass
>>> class Thing(object):
...     __metaclass__ = MyMeta
>>> schema = Schema(Thing)
>>> t = schema(Thing())
>>> type(t) is Thing
True

Schemas built with All() should give the same error as the original validator (Issue #26):

>>> schema = Schema({
...   Required('items'): All([{
...     Required('foo'): str
...   }])
... })

>>> schema({'items': [{}]})
Traceback (most recent call last):
...
MultipleInvalid: required key not provided @ data['items'][0]['foo']

Validator should return same instance of the same type for object:

>>> class Structure(object):
...     def __init__(self, q=None):
...         self.q = q
...     def __repr__(self):
...         return '{0.__name__}(q={1.q!r})'.format(type(self), self)
...
>>> schema = Schema(Object({'q': 'one'}, cls=Structure))
>>> type(schema(Structure(q='one'))) is Structure
True

Object validator should treat cls argument as optional. In this case it shouldn't check object type:

>>> from collections import namedtuple
>>> NamedTuple = namedtuple('NamedTuple', ('q',))
>>> schema = Schema(Object({'q': 'one'}))
>>> named = NamedTuple(q='one')
>>> schema(named) == named
True
>>> schema(named)
NamedTuple(q='one')

If cls argument passed to object validator we should check object type:

>>> schema = Schema(Object({'q': 'one'}, cls=Structure))
>>> schema(NamedTuple(q='one'))  # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
MultipleInvalid: expected a <class 'Structure'>
>>> schema = Schema(Object({'q': 'one'}, cls=NamedTuple))
>>> schema(NamedTuple(q='one'))
NamedTuple(q='one')

Ensure that objects with __slots__ supported properly:

>>> class SlotsStructure(Structure):
...     __slots__ = ['q']
...
>>> schema = Schema(Object({'q': 'one'}))
>>> schema(SlotsStructure(q='one'))
SlotsStructure(q='one')
>>> class DictStructure(object):
...     __slots__ = ['q', '__dict__']
...     def __init__(self, q=None, page=None):
...         self.q = q
...         self.page = page
...     def __repr__(self):
...         return '{0.__name__}(q={1.q!r}, page={1.page!r})'.format(type(self), self)
...
>>> structure = DictStructure(q='one')
>>> structure.page = 1
>>> schema(structure)
Traceback (most recent call last):
...
MultipleInvalid: extra keys not allowed @ data['page']
>>> schema = Schema(Object({'q': 'one', Extra: object}))
>>> schema(structure)
DictStructure(q='one', page=1)

Ensure that objects can be used with other validators:

>>> schema = Schema({'meta': Object({'q': 'one'})})
>>> schema({'meta': Structure(q='one')})
{'meta': Structure(q='one')}