summaryrefslogtreecommitdiffstats
path: root/ipatests/test_ipalib/test_parameters.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipatests/test_ipalib/test_parameters.py')
-rw-r--r--ipatests/test_ipalib/test_parameters.py1533
1 files changed, 1533 insertions, 0 deletions
diff --git a/ipatests/test_ipalib/test_parameters.py b/ipatests/test_ipalib/test_parameters.py
new file mode 100644
index 000000000..71acfce71
--- /dev/null
+++ b/ipatests/test_ipalib/test_parameters.py
@@ -0,0 +1,1533 @@
+# -*- coding: utf-8 -*-
+# Authors:
+# Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Test the `ipalib.parameters` module.
+"""
+
+import re
+import sys
+from types import NoneType
+from decimal import Decimal
+from inspect import isclass
+from ipatests.util import raises, ClassChecker, read_only
+from ipatests.util import dummy_ugettext, assert_equal
+from ipatests.data import binary_bytes, utf8_bytes, unicode_str
+from ipalib import parameters, text, errors, config
+from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR, NULLS
+from ipalib.errors import ValidationError, ConversionError
+from ipalib import _
+from xmlrpclib import MAXINT, MININT
+
+class test_DefaultFrom(ClassChecker):
+ """
+ Test the `ipalib.parameters.DefaultFrom` class.
+ """
+ _cls = parameters.DefaultFrom
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.DefaultFrom.__init__` method.
+ """
+ def callback(*args):
+ return args
+ keys = ('givenname', 'sn')
+ o = self.cls(callback, *keys)
+ assert read_only(o, 'callback') is callback
+ assert read_only(o, 'keys') == keys
+ lam = lambda first, last: first[0] + last
+ o = self.cls(lam)
+ assert read_only(o, 'keys') == ('first', 'last')
+
+ # Test that TypeError is raised when callback isn't callable:
+ e = raises(TypeError, self.cls, 'whatever')
+ assert str(e) == CALLABLE_ERROR % ('callback', 'whatever', str)
+
+ # Test that TypeError is raised when a key isn't an str:
+ e = raises(TypeError, self.cls, callback, 'givenname', 17)
+ assert str(e) == TYPE_ERROR % ('keys', str, 17, int)
+
+ # Test that ValueError is raised when inferring keys from a callback
+ # which has *args:
+ e = raises(ValueError, self.cls, lambda foo, *args: None)
+ assert str(e) == "callback: variable-length argument list not allowed"
+
+ # Test that ValueError is raised when inferring keys from a callback
+ # which has **kwargs:
+ e = raises(ValueError, self.cls, lambda foo, **kwargs: None)
+ assert str(e) == "callback: variable-length argument list not allowed"
+
+ def test_repr(self):
+ """
+ Test the `ipalib.parameters.DefaultFrom.__repr__` method.
+ """
+ def stuff(one, two):
+ pass
+
+ o = self.cls(stuff)
+ assert repr(o) == "DefaultFrom(stuff, 'one', 'two')"
+
+ o = self.cls(stuff, 'aye', 'bee', 'see')
+ assert repr(o) == "DefaultFrom(stuff, 'aye', 'bee', 'see')"
+
+ cb = lambda first, last: first[0] + last
+
+ o = self.cls(cb)
+ assert repr(o) == "DefaultFrom(<lambda>, 'first', 'last')"
+
+ o = self.cls(cb, 'aye', 'bee', 'see')
+ assert repr(o) == "DefaultFrom(<lambda>, 'aye', 'bee', 'see')"
+
+ def test_call(self):
+ """
+ Test the `ipalib.parameters.DefaultFrom.__call__` method.
+ """
+ def callback(givenname, sn):
+ return givenname[0] + sn[0]
+ keys = ('givenname', 'sn')
+ o = self.cls(callback, *keys)
+ kw = dict(
+ givenname='John',
+ sn='Public',
+ hello='world',
+ )
+ assert o(**kw) == 'JP'
+ assert o() is None
+ for key in ('givenname', 'sn'):
+ kw_copy = dict(kw)
+ del kw_copy[key]
+ assert o(**kw_copy) is None
+
+ # Test using implied keys:
+ o = self.cls(lambda first, last: first[0] + last)
+ assert o(first='john', last='doe') == 'jdoe'
+ assert o(first='', last='doe') is None
+ assert o(one='john', two='doe') is None
+
+ # Test that co_varnames slice is used:
+ def callback2(first, last):
+ letter = first[0]
+ return letter + last
+ o = self.cls(callback2)
+ assert o.keys == ('first', 'last')
+ assert o(first='john', last='doe') == 'jdoe'
+
+
+def test_parse_param_spec():
+ """
+ Test the `ipalib.parameters.parse_param_spec` function.
+ """
+ f = parameters.parse_param_spec
+ assert f('name') == ('name', dict(required=True, multivalue=False))
+ assert f('name?') == ('name', dict(required=False, multivalue=False))
+ assert f('name*') == ('name', dict(required=False, multivalue=True))
+ assert f('name+') == ('name', dict(required=True, multivalue=True))
+
+ # Make sure other "funny" endings are *not* treated special:
+ assert f('name^') == ('name^', dict(required=True, multivalue=False))
+
+ # Test that TypeError is raised if spec isn't an str:
+ e = raises(TypeError, f, u'name?')
+ assert str(e) == TYPE_ERROR % ('spec', str, u'name?', unicode)
+
+
+class DummyRule(object):
+ def __init__(self, error=None):
+ assert error is None or type(error) is unicode
+ self.error = error
+ self.reset()
+
+ def __call__(self, *args):
+ self.calls.append(args)
+ return self.error
+
+ def reset(self):
+ self.calls = []
+
+
+class test_Param(ClassChecker):
+ """
+ Test the `ipalib.parameters.Param` class.
+ """
+ _cls = parameters.Param
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Param.__init__` method.
+ """
+ name = 'my_param'
+ o = self.cls(name)
+ assert o.param_spec is name
+ assert o.name is name
+ assert o.nice == "Param('my_param')"
+ assert o.password is False
+ assert o.__islocked__() is True
+
+ # Test default rules:
+ assert o.rules == tuple()
+ assert o.class_rules == tuple()
+ assert o.all_rules == tuple()
+
+ # Test default kwarg values:
+ assert o.cli_name is name
+ assert o.label.msg == 'my_param'
+ assert o.doc.msg == 'my_param'
+ assert o.required is True
+ assert o.multivalue is False
+ assert o.primary_key is False
+ assert o.normalizer is None
+ assert o.default is None
+ assert o.default_from is None
+ assert o.autofill is False
+ assert o.query is False
+ assert o.attribute is False
+ assert o.include is None
+ assert o.exclude is None
+ assert o.flags == frozenset()
+ assert o.sortorder == 2
+ assert o.csv is False
+
+ # Test that doc defaults from label:
+ o = self.cls('my_param', doc=_('Hello world'))
+ assert o.label.msg == 'my_param'
+ assert o.doc.msg == 'Hello world'
+
+ o = self.cls('my_param', label='My Param')
+ assert o.label == 'My Param'
+ assert o.doc == 'My Param'
+
+
+ # Test that ValueError is raised when a kwarg from a subclass
+ # conflicts with an attribute:
+ class Subclass(self.cls):
+ kwargs = self.cls.kwargs + (
+ ('convert', callable, None),
+ )
+ e = raises(ValueError, Subclass, name)
+ assert str(e) == "kwarg 'convert' conflicts with attribute on Subclass"
+
+ # Test type validation of keyword arguments:
+ class Subclass(self.cls):
+ kwargs = self.cls.kwargs + (
+ ('extra1', bool, True),
+ ('extra2', str, 'Hello'),
+ ('extra3', (int, float), 42),
+ ('extra4', callable, lambda whatever: whatever + 7),
+ )
+ o = Subclass('my_param') # Test with no **kw:
+ for (key, kind, default) in o.kwargs:
+ # Test with a type invalid for all:
+ value = object()
+ kw = {key: value}
+ e = raises(TypeError, Subclass, 'my_param', **kw)
+ if kind is callable:
+ assert str(e) == CALLABLE_ERROR % (key, value, type(value))
+ else:
+ assert str(e) == TYPE_ERROR % (key, kind, value, type(value))
+ # Test with None:
+ kw = {key: None}
+ Subclass('my_param', **kw)
+
+ # Test when using unknown kwargs:
+ e = raises(TypeError, self.cls, 'my_param',
+ flags=['hello', 'world'],
+ whatever=u'Hooray!',
+ )
+ assert str(e) == \
+ "Param('my_param'): takes no such kwargs: 'whatever'"
+ e = raises(TypeError, self.cls, 'my_param', great='Yes', ape='he is!')
+ assert str(e) == \
+ "Param('my_param'): takes no such kwargs: 'ape', 'great'"
+
+ # Test that ValueError is raised if you provide both include and
+ # exclude:
+ e = raises(ValueError, self.cls, 'my_param',
+ include=['server', 'foo'],
+ exclude=['client', 'bar'],
+ )
+ assert str(e) == '%s: cannot have both %s=%r and %s=%r' % (
+ "Param('my_param')",
+ 'include', frozenset(['server', 'foo']),
+ 'exclude', frozenset(['client', 'bar']),
+ )
+
+ # Test that ValueError is raised if csv is set and multivalue is not set:
+ e = raises(ValueError, self.cls, 'my_param', csv=True)
+ assert str(e) == '%s: cannot have csv without multivalue' % "Param('my_param')"
+
+ # Test that default_from gets set:
+ call = lambda first, last: first[0] + last
+ o = self.cls('my_param', default_from=call)
+ assert type(o.default_from) is parameters.DefaultFrom
+ assert o.default_from.callback is call
+
+ def test_repr(self):
+ """
+ Test the `ipalib.parameters.Param.__repr__` method.
+ """
+ for name in ['name', 'name?', 'name*', 'name+']:
+ o = self.cls(name)
+ assert repr(o) == 'Param(%r)' % name
+ o = self.cls('name', required=False)
+ assert repr(o) == "Param('name', required=False)"
+ o = self.cls('name', multivalue=True)
+ assert repr(o) == "Param('name', multivalue=True)"
+
+ def test_use_in_context(self):
+ """
+ Test the `ipalib.parameters.Param.use_in_context` method.
+ """
+ set1 = ('one', 'two', 'three')
+ set2 = ('four', 'five', 'six')
+ param1 = self.cls('param1')
+ param2 = self.cls('param2', include=set1)
+ param3 = self.cls('param3', exclude=set2)
+ for context in set1:
+ env = config.Env()
+ env.context = context
+ assert param1.use_in_context(env) is True, context
+ assert param2.use_in_context(env) is True, context
+ assert param3.use_in_context(env) is True, context
+ for context in set2:
+ env = config.Env()
+ env.context = context
+ assert param1.use_in_context(env) is True, context
+ assert param2.use_in_context(env) is False, context
+ assert param3.use_in_context(env) is False, context
+
+ def test_safe_value(self):
+ """
+ Test the `ipalib.parameters.Param.safe_value` method.
+ """
+ values = (unicode_str, binary_bytes, utf8_bytes)
+ o = self.cls('my_param')
+ for value in values:
+ assert o.safe_value(value) is value
+ assert o.safe_value(None) is None
+ p = parameters.Password('my_passwd')
+ for value in values:
+ assert_equal(p.safe_value(value), u'********')
+ assert p.safe_value(None) is None
+
+ def test_clone(self):
+ """
+ Test the `ipalib.parameters.Param.clone` method.
+ """
+ # Test with the defaults
+ orig = self.cls('my_param')
+ clone = orig.clone()
+ assert clone is not orig
+ assert type(clone) is self.cls
+ assert clone.name is orig.name
+ for (key, kind, default) in self.cls.kwargs:
+ assert getattr(clone, key) is getattr(orig, key)
+
+ # Test with a param spec:
+ orig = self.cls('my_param*')
+ assert orig.param_spec == 'my_param*'
+ clone = orig.clone()
+ assert clone.param_spec == 'my_param'
+ assert clone is not orig
+ assert type(clone) is self.cls
+ for (key, kind, default) in self.cls.kwargs:
+ assert getattr(clone, key) is getattr(orig, key)
+
+ # Test with overrides:
+ orig = self.cls('my_param*')
+ assert orig.required is False
+ assert orig.multivalue is True
+ clone = orig.clone(required=True)
+ assert clone is not orig
+ assert type(clone) is self.cls
+ assert clone.required is True
+ assert clone.multivalue is True
+ assert clone.param_spec == 'my_param'
+ assert clone.name == 'my_param'
+
+ def test_clone_rename(self):
+ """
+ Test the `ipalib.parameters.Param.clone` method.
+ """
+ new_name = 'my_new_param'
+
+ # Test with the defaults
+ orig = self.cls('my_param')
+ clone = orig.clone_rename(new_name)
+ assert clone is not orig
+ assert type(clone) is self.cls
+ assert clone.name == new_name
+ for (key, kind, default) in self.cls.kwargs:
+ assert getattr(clone, key) is getattr(orig, key)
+
+ # Test with overrides:
+ orig = self.cls('my_param*')
+ assert orig.required is False
+ assert orig.multivalue is True
+ clone = orig.clone_rename(new_name, required=True)
+ assert clone is not orig
+ assert type(clone) is self.cls
+ assert clone.required is True
+ assert clone.multivalue is True
+ assert clone.param_spec == new_name
+ assert clone.name == new_name
+
+
+ def test_convert(self):
+ """
+ Test the `ipalib.parameters.Param.convert` method.
+ """
+ okay = ('Hello', u'Hello', 0, 4.2, True, False, unicode_str)
+ class Subclass(self.cls):
+ def _convert_scalar(self, value, index=None):
+ return value
+
+ # Test when multivalue=False:
+ o = Subclass('my_param')
+ for value in NULLS:
+ assert o.convert(value) is None
+ assert o.convert(None) is None
+ for value in okay:
+ assert o.convert(value) is value
+
+ # Test when multivalue=True:
+ o = Subclass('my_param', multivalue=True)
+ for value in NULLS:
+ assert o.convert(value) is None
+ assert o.convert(okay) == okay
+ assert o.convert(NULLS) is None
+ assert o.convert(okay + NULLS) == okay
+ assert o.convert(NULLS + okay) == okay
+ for value in okay:
+ assert o.convert(value) == (value,)
+ assert o.convert([None, value]) == (value,)
+ assert o.convert([value, None]) == (value,)
+
+ def test_convert_scalar(self):
+ """
+ Test the `ipalib.parameters.Param._convert_scalar` method.
+ """
+ dummy = dummy_ugettext()
+
+ # Test with correct type:
+ o = self.cls('my_param')
+ assert o._convert_scalar(None) is None
+ assert dummy.called() is False
+ # Test with incorrect type
+ e = raises(errors.ConversionError, o._convert_scalar, 'hello', index=17)
+
+ def test_validate(self):
+ """
+ Test the `ipalib.parameters.Param.validate` method.
+ """
+
+ # Test in default state (with no rules, no kwarg):
+ o = self.cls('my_param')
+ e = raises(errors.RequirementError, o.validate, None, 'cli')
+ assert e.name == 'my_param'
+
+ # Test in default state that cli_name gets returned in the exception
+ # when context == 'cli'
+ o = self.cls('my_param', cli_name='short')
+ e = raises(errors.RequirementError, o.validate, None, 'cli')
+ assert e.name == 'short'
+
+ # Test with required=False
+ o = self.cls('my_param', required=False)
+ assert o.required is False
+ assert o.validate(None, 'cli') is None
+
+ # Test with query=True:
+ o = self.cls('my_param', query=True)
+ assert o.query is True
+ e = raises(errors.RequirementError, o.validate, None, 'cli')
+ assert_equal(e.name, 'my_param')
+
+ # Test with multivalue=True:
+ o = self.cls('my_param', multivalue=True)
+ e = raises(TypeError, o.validate, [], 'cli')
+ assert str(e) == TYPE_ERROR % ('value', tuple, [], list)
+ e = raises(ValueError, o.validate, tuple(), 'cli')
+ assert str(e) == 'value: empty tuple must be converted to None'
+
+ # Test with wrong (scalar) type:
+ e = raises(TypeError, o.validate, (None, None, 42, None), 'cli')
+ assert str(e) == TYPE_ERROR % ('my_param', NoneType, 42, int)
+ o = self.cls('my_param')
+ e = raises(TypeError, o.validate, 'Hello', 'cli')
+ assert str(e) == TYPE_ERROR % ('my_param', NoneType, 'Hello', str)
+
+ class Example(self.cls):
+ type = int
+
+ # Test with some rules and multivalue=False
+ pass1 = DummyRule()
+ pass2 = DummyRule()
+ fail = DummyRule(u'no good')
+ o = Example('example', pass1, pass2)
+ assert o.multivalue is False
+ assert o.validate(11, 'cli') is None
+ assert pass1.calls == [(text.ugettext, 11)]
+ assert pass2.calls == [(text.ugettext, 11)]
+ pass1.reset()
+ pass2.reset()
+ o = Example('example', pass1, pass2, fail)
+ e = raises(errors.ValidationError, o.validate, 42, 'cli')
+ assert e.name == 'example'
+ assert e.error == u'no good'
+ assert e.index is None
+ assert pass1.calls == [(text.ugettext, 42)]
+ assert pass2.calls == [(text.ugettext, 42)]
+ assert fail.calls == [(text.ugettext, 42)]
+
+ # Test with some rules and multivalue=True
+ pass1 = DummyRule()
+ pass2 = DummyRule()
+ fail = DummyRule(u'this one is not good')
+ o = Example('example', pass1, pass2, multivalue=True)
+ assert o.multivalue is True
+ assert o.validate((3, 9), 'cli') is None
+ assert pass1.calls == [
+ (text.ugettext, 3),
+ (text.ugettext, 9),
+ ]
+ assert pass2.calls == [
+ (text.ugettext, 3),
+ (text.ugettext, 9),
+ ]
+ pass1.reset()
+ pass2.reset()
+ o = Example('multi_example', pass1, pass2, fail, multivalue=True)
+ assert o.multivalue is True
+ e = raises(errors.ValidationError, o.validate, (3, 9), 'cli')
+ assert e.name == 'multi_example'
+ assert e.error == u'this one is not good'
+ assert e.index == 0
+ assert pass1.calls == [(text.ugettext, 3)]
+ assert pass2.calls == [(text.ugettext, 3)]
+ assert fail.calls == [(text.ugettext, 3)]
+
+ def test_validate_scalar(self):
+ """
+ Test the `ipalib.parameters.Param._validate_scalar` method.
+ """
+ class MyParam(self.cls):
+ type = bool
+ okay = DummyRule()
+ o = MyParam('my_param', okay)
+
+ # Test that TypeError is appropriately raised:
+ e = raises(TypeError, o._validate_scalar, 0)
+ assert str(e) == TYPE_ERROR % ('my_param', bool, 0, int)
+ e = raises(TypeError, o._validate_scalar, 'Hi', index=4)
+ assert str(e) == TYPE_ERROR % ('my_param', bool, 'Hi', str)
+ e = raises(TypeError, o._validate_scalar, True, index=3.0)
+ assert str(e) == TYPE_ERROR % ('index', int, 3.0, float)
+
+ # Test with passing rule:
+ assert o._validate_scalar(True, index=None) is None
+ assert o._validate_scalar(False, index=None) is None
+ assert okay.calls == [
+ (text.ugettext, True),
+ (text.ugettext, False),
+ ]
+
+ # Test with a failing rule:
+ okay = DummyRule()
+ fail = DummyRule(u'this describes the error')
+ o = MyParam('my_param', okay, fail)
+ e = raises(errors.ValidationError, o._validate_scalar, True)
+ assert e.name == 'my_param'
+ assert e.error == u'this describes the error'
+ assert e.index is None
+ e = raises(errors.ValidationError, o._validate_scalar, False, index=2)
+ assert e.name == 'my_param'
+ assert e.error == u'this describes the error'
+ assert e.index == 2
+ assert okay.calls == [
+ (text.ugettext, True),
+ (text.ugettext, False),
+ ]
+ assert fail.calls == [
+ (text.ugettext, True),
+ (text.ugettext, False),
+ ]
+
+ def test_get_default(self):
+ """
+ Test the `ipalib.parameters.Param.get_default` method.
+ """
+ class PassThrough(object):
+ value = None
+
+ def __call__(self, value):
+ assert self.value is None
+ assert value is not None
+ self.value = value
+ return value
+
+ def reset(self):
+ assert self.value is not None
+ self.value = None
+
+ class Str(self.cls):
+ type = unicode
+
+ def __init__(self, name, **kw):
+ self._convert_scalar = PassThrough()
+ super(Str, self).__init__(name, **kw)
+
+ # Test with only a static default:
+ o = Str('my_str',
+ normalizer=PassThrough(),
+ default=u'Static Default',
+ )
+ assert_equal(o.get_default(), u'Static Default')
+ assert o._convert_scalar.value is None
+ assert o.normalizer.value is None
+
+ # Test with default_from:
+ o = Str('my_str',
+ normalizer=PassThrough(),
+ default=u'Static Default',
+ default_from=lambda first, last: first[0] + last,
+ )
+ assert_equal(o.get_default(), u'Static Default')
+ assert o._convert_scalar.value is None
+ assert o.normalizer.value is None
+ default = o.get_default(first=u'john', last='doe')
+ assert_equal(default, u'jdoe')
+ assert o._convert_scalar.value is default
+ assert o.normalizer.value is default
+
+
+class test_Flag(ClassChecker):
+ """
+ Test the `ipalib.parameters.Flag` class.
+ """
+ _cls = parameters.Flag
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Flag.__init__` method.
+ """
+ # Test with no kwargs:
+ o = self.cls('my_flag')
+ assert o.type is bool
+ assert isinstance(o, parameters.Bool)
+ assert o.autofill is True
+ assert o.default is False
+
+ # Test that TypeError is raise if default is not a bool:
+ e = raises(TypeError, self.cls, 'my_flag', default=None)
+ assert str(e) == TYPE_ERROR % ('default', bool, None, NoneType)
+
+ # Test with autofill=False, default=True
+ o = self.cls('my_flag', autofill=False, default=True)
+ assert o.autofill is True
+ assert o.default is True
+
+ # Test when cloning:
+ orig = self.cls('my_flag')
+ for clone in [orig.clone(), orig.clone(autofill=False)]:
+ assert clone.autofill is True
+ assert clone.default is False
+ assert clone is not orig
+ assert type(clone) is self.cls
+
+ # Test when cloning with default=True/False
+ orig = self.cls('my_flag')
+ assert orig.clone().default is False
+ assert orig.clone(default=True).default is True
+ orig = self.cls('my_flag', default=True)
+ assert orig.clone().default is True
+ assert orig.clone(default=False).default is False
+
+
+class test_Data(ClassChecker):
+ """
+ Test the `ipalib.parameters.Data` class.
+ """
+ _cls = parameters.Data
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Data.__init__` method.
+ """
+ o = self.cls('my_data')
+ assert o.type is NoneType
+ assert o.password is False
+ assert o.rules == tuple()
+ assert o.class_rules == tuple()
+ assert o.all_rules == tuple()
+ assert o.minlength is None
+ assert o.maxlength is None
+ assert o.length is None
+ assert o.pattern is None
+
+ # Test mixing length with minlength or maxlength:
+ o = self.cls('my_data', length=5)
+ assert o.length == 5
+ permutations = [
+ dict(minlength=3),
+ dict(maxlength=7),
+ dict(minlength=3, maxlength=7),
+ ]
+ for kw in permutations:
+ o = self.cls('my_data', **kw)
+ for (key, value) in kw.iteritems():
+ assert getattr(o, key) == value
+ e = raises(ValueError, self.cls, 'my_data', length=5, **kw)
+ assert str(e) == \
+ "Data('my_data'): cannot mix length with minlength or maxlength"
+
+ # Test when minlength or maxlength are less than 1:
+ e = raises(ValueError, self.cls, 'my_data', minlength=0)
+ assert str(e) == "Data('my_data'): minlength must be >= 1; got 0"
+ e = raises(ValueError, self.cls, 'my_data', maxlength=0)
+ assert str(e) == "Data('my_data'): maxlength must be >= 1; got 0"
+
+ # Test when minlength > maxlength:
+ e = raises(ValueError, self.cls, 'my_data', minlength=22, maxlength=15)
+ assert str(e) == \
+ "Data('my_data'): minlength > maxlength (minlength=22, maxlength=15)"
+
+ # Test when minlength == maxlength
+ e = raises(ValueError, self.cls, 'my_data', minlength=7, maxlength=7)
+ assert str(e) == \
+ "Data('my_data'): minlength == maxlength; use length=7 instead"
+
+
+class test_Bytes(ClassChecker):
+ """
+ Test the `ipalib.parameters.Bytes` class.
+ """
+ _cls = parameters.Bytes
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Bytes.__init__` method.
+ """
+ o = self.cls('my_bytes')
+ assert o.type is str
+ assert o.password is False
+ assert o.rules == tuple()
+ assert o.class_rules == tuple()
+ assert o.all_rules == tuple()
+ assert o.minlength is None
+ assert o.maxlength is None
+ assert o.length is None
+ assert o.pattern is None
+ assert o.re is None
+
+ # Test mixing length with minlength or maxlength:
+ o = self.cls('my_bytes', length=5)
+ assert o.length == 5
+ assert len(o.class_rules) == 1
+ assert len(o.rules) == 0
+ assert len(o.all_rules) == 1
+ permutations = [
+ dict(minlength=3),
+ dict(maxlength=7),
+ dict(minlength=3, maxlength=7),
+ ]
+ for kw in permutations:
+ o = self.cls('my_bytes', **kw)
+ assert len(o.class_rules) == len(kw)
+ assert len(o.rules) == 0
+ assert len(o.all_rules) == len(kw)
+ for (key, value) in kw.iteritems():
+ assert getattr(o, key) == value
+ e = raises(ValueError, self.cls, 'my_bytes', length=5, **kw)
+ assert str(e) == \
+ "Bytes('my_bytes'): cannot mix length with minlength or maxlength"
+
+ # Test when minlength or maxlength are less than 1:
+ e = raises(ValueError, self.cls, 'my_bytes', minlength=0)
+ assert str(e) == "Bytes('my_bytes'): minlength must be >= 1; got 0"
+ e = raises(ValueError, self.cls, 'my_bytes', maxlength=0)
+ assert str(e) == "Bytes('my_bytes'): maxlength must be >= 1; got 0"
+
+ # Test when minlength > maxlength:
+ e = raises(ValueError, self.cls, 'my_bytes', minlength=22, maxlength=15)
+ assert str(e) == \
+ "Bytes('my_bytes'): minlength > maxlength (minlength=22, maxlength=15)"
+
+ # Test when minlength == maxlength
+ e = raises(ValueError, self.cls, 'my_bytes', minlength=7, maxlength=7)
+ assert str(e) == \
+ "Bytes('my_bytes'): minlength == maxlength; use length=7 instead"
+
+ def test_rule_minlength(self):
+ """
+ Test the `ipalib.parameters.Bytes._rule_minlength` method.
+ """
+ o = self.cls('my_bytes', minlength=3)
+ assert o.minlength == 3
+ rule = o._rule_minlength
+ translation = u'minlength=%(minlength)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in ('abc', 'four', '12345'):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in ('', 'a', '12'):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(minlength=3)
+ )
+ assert dummy.message == 'must be at least %(minlength)d bytes'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_rule_maxlength(self):
+ """
+ Test the `ipalib.parameters.Bytes._rule_maxlength` method.
+ """
+ o = self.cls('my_bytes', maxlength=4)
+ assert o.maxlength == 4
+ rule = o._rule_maxlength
+ translation = u'maxlength=%(maxlength)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in ('ab', '123', 'four'):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in ('12345', 'sixsix'):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(maxlength=4)
+ )
+ assert dummy.message == 'can be at most %(maxlength)d bytes'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_rule_length(self):
+ """
+ Test the `ipalib.parameters.Bytes._rule_length` method.
+ """
+ o = self.cls('my_bytes', length=4)
+ assert o.length == 4
+ rule = o._rule_length
+ translation = u'length=%(length)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in ('1234', 'four'):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in ('ab', '123', '12345', 'sixsix'):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(length=4),
+ )
+ assert dummy.message == 'must be exactly %(length)d bytes'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_rule_pattern(self):
+ """
+ Test the `ipalib.parameters.Bytes._rule_pattern` method.
+ """
+ # Test our assumptions about Python re module and Unicode:
+ pat = '\w+$'
+ r = re.compile(pat)
+ assert r.match('Hello_World') is not None
+ assert r.match(utf8_bytes) is None
+ assert r.match(binary_bytes) is None
+
+ # Create instance:
+ o = self.cls('my_bytes', pattern=pat)
+ assert o.pattern is pat
+ rule = o._rule_pattern
+ translation = u'pattern=%(pattern)r'
+ dummy = dummy_ugettext(translation)
+
+ # Test with passing values:
+ for value in ('HELLO', 'hello', 'Hello_World'):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in ('Hello!', 'Hello World', utf8_bytes, binary_bytes):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(pattern=pat),
+ )
+ assert_equal(dummy.message, 'must match pattern "%(pattern)s"')
+ assert dummy.called() is True
+ dummy.reset()
+
+
+class test_Str(ClassChecker):
+ """
+ Test the `ipalib.parameters.Str` class.
+ """
+ _cls = parameters.Str
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Str.__init__` method.
+ """
+ o = self.cls('my_str')
+ assert o.type is unicode
+ assert o.password is False
+ assert o.minlength is None
+ assert o.maxlength is None
+ assert o.length is None
+ assert o.pattern is None
+
+ def test_convert_scalar(self):
+ """
+ Test the `ipalib.parameters.Str._convert_scalar` method.
+ """
+ o = self.cls('my_str')
+ mthd = o._convert_scalar
+ for value in (u'Hello', 42, 1.2, unicode_str):
+ assert mthd(value) == unicode(value)
+ bad = [True, 'Hello', dict(one=1), utf8_bytes]
+ for value in bad:
+ e = raises(errors.ConversionError, mthd, value)
+ assert e.name == 'my_str'
+ assert e.index is None
+ assert_equal(unicode(e.error), u'must be Unicode text')
+ e = raises(errors.ConversionError, mthd, value, index=18)
+ assert e.name == 'my_str'
+ assert e.index == 18
+ assert_equal(unicode(e.error), u'must be Unicode text')
+ bad = [(u'Hello',), [42.3]]
+ for value in bad:
+ e = raises(errors.ConversionError, mthd, value)
+ assert e.name == 'my_str'
+ assert e.index is None
+ assert_equal(unicode(e.error), u'Only one value is allowed')
+ assert o.convert(None) is None
+
+ def test_rule_minlength(self):
+ """
+ Test the `ipalib.parameters.Str._rule_minlength` method.
+ """
+ o = self.cls('my_str', minlength=3)
+ assert o.minlength == 3
+ rule = o._rule_minlength
+ translation = u'minlength=%(minlength)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in (u'abc', u'four', u'12345'):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in (u'', u'a', u'12'):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(minlength=3)
+ )
+ assert dummy.message == 'must be at least %(minlength)d characters'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_rule_maxlength(self):
+ """
+ Test the `ipalib.parameters.Str._rule_maxlength` method.
+ """
+ o = self.cls('my_str', maxlength=4)
+ assert o.maxlength == 4
+ rule = o._rule_maxlength
+ translation = u'maxlength=%(maxlength)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in (u'ab', u'123', u'four'):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in (u'12345', u'sixsix'):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(maxlength=4)
+ )
+ assert dummy.message == 'can be at most %(maxlength)d characters'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_rule_length(self):
+ """
+ Test the `ipalib.parameters.Str._rule_length` method.
+ """
+ o = self.cls('my_str', length=4)
+ assert o.length == 4
+ rule = o._rule_length
+ translation = u'length=%(length)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in (u'1234', u'four'):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in (u'ab', u'123', u'12345', u'sixsix'):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(length=4),
+ )
+ assert dummy.message == 'must be exactly %(length)d characters'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_rule_pattern(self):
+ """
+ Test the `ipalib.parameters.Str._rule_pattern` method.
+ """
+ # Test our assumptions about Python re module and Unicode:
+ pat = '\w{5}$'
+ r1 = re.compile(pat)
+ r2 = re.compile(pat, re.UNICODE)
+ assert r1.match(unicode_str) is None
+ assert r2.match(unicode_str) is not None
+
+ # Create instance:
+ o = self.cls('my_str', pattern=pat)
+ assert o.pattern is pat
+ rule = o._rule_pattern
+ translation = u'pattern=%(pattern)r'
+ dummy = dummy_ugettext(translation)
+
+ # Test with passing values:
+ for value in (u'HELLO', u'hello', unicode_str):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in (u'H LLO', u'***lo', unicode_str + unicode_str):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(pattern=pat),
+ )
+ assert_equal(dummy.message, 'must match pattern "%(pattern)s"')
+ assert dummy.called() is True
+ dummy.reset()
+
+
+class test_Password(ClassChecker):
+ """
+ Test the `ipalib.parameters.Password` class.
+ """
+ _cls = parameters.Password
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Password.__init__` method.
+ """
+ o = self.cls('my_password')
+ assert o.type is unicode
+ assert o.minlength is None
+ assert o.maxlength is None
+ assert o.length is None
+ assert o.pattern is None
+ assert o.password is True
+
+ def test_convert_scalar(self):
+ """
+ Test the `ipalib.parameters.Password._convert_scalar` method.
+ """
+ o = self.cls('my_password')
+ e = raises(errors.PasswordMismatch, o._convert_scalar, [u'one', u'two'])
+ assert e.name == 'my_password'
+ assert e.index is None
+ assert o._convert_scalar([u'one', u'one']) == u'one'
+ assert o._convert_scalar(u'one') == u'one'
+
+
+class test_StrEnum(ClassChecker):
+ """
+ Test the `ipalib.parameters.StrEnum` class.
+ """
+ _cls = parameters.StrEnum
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.StrEnum.__init__` method.
+ """
+ values = (u'Hello', u'naughty', u'nurse!')
+ o = self.cls('my_strenum', values=values)
+ assert o.type is unicode
+ assert o.values is values
+ assert o.class_rules == (o._rule_values,)
+ assert o.rules == tuple()
+ assert o.all_rules == (o._rule_values,)
+
+ badvalues = (u'Hello', 'naughty', u'nurse!')
+ e = raises(TypeError, self.cls, 'my_enum', values=badvalues)
+ assert str(e) == TYPE_ERROR % (
+ "StrEnum('my_enum') values[1]", unicode, 'naughty', str
+ )
+
+ # Test that ValueError is raised when list of values is empty
+ badvalues = tuple()
+ e = raises(ValueError, self.cls, 'empty_enum', values=badvalues)
+ assert_equal(str(e), "StrEnum('empty_enum'): list of values must not "
+ "be empty")
+
+ def test_rules_values(self):
+ """
+ Test the `ipalib.parameters.StrEnum._rule_values` method.
+ """
+ values = (u'Hello', u'naughty', u'nurse!')
+ o = self.cls('my_enum', values=values)
+ rule = o._rule_values
+ translation = u"values='Hello', 'naughty', 'nurse!'"
+ dummy = dummy_ugettext(translation)
+
+ # Test with passing values:
+ for v in values:
+ assert rule(dummy, v) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for val in (u'Howdy', u'quiet', u'library!'):
+ assert_equal(
+ rule(dummy, val),
+ translation % dict(values=values),
+ )
+ assert_equal(dummy.message, "must be one of %(values)s")
+ dummy.reset()
+
+ # test a special case when we have just one allowed value
+ values = (u'Hello', )
+ o = self.cls('my_enum', values=values)
+ rule = o._rule_values
+ translation = u"value='Hello'"
+ dummy = dummy_ugettext(translation)
+
+ for val in (u'Howdy', u'quiet', u'library!'):
+ assert_equal(
+ rule(dummy, val),
+ translation % dict(values=values),
+ )
+ assert_equal(dummy.message, "must be '%(value)s'")
+ dummy.reset()
+
+
+class test_Number(ClassChecker):
+ """
+ Test the `ipalib.parameters.Number` class.
+ """
+ _cls = parameters.Number
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Number.__init__` method.
+ """
+ o = self.cls('my_number')
+ assert o.type is NoneType
+ assert o.password is False
+ assert o.rules == tuple()
+ assert o.class_rules == tuple()
+ assert o.all_rules == tuple()
+
+
+
+class test_Int(ClassChecker):
+ """
+ Test the `ipalib.parameters.Int` class.
+ """
+ _cls = parameters.Int
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Int.__init__` method.
+ """
+ # Test with no kwargs:
+ o = self.cls('my_number')
+ assert o.type is int
+ assert isinstance(o, parameters.Int)
+ assert o.minvalue == int(MININT)
+ assert o.maxvalue == int(MAXINT)
+
+ # Test when min > max:
+ e = raises(ValueError, self.cls, 'my_number', minvalue=22, maxvalue=15)
+ assert str(e) == \
+ "Int('my_number'): minvalue > maxvalue (minvalue=22, maxvalue=15)"
+
+ def test_rule_minvalue(self):
+ """
+ Test the `ipalib.parameters.Int._rule_minvalue` method.
+ """
+ o = self.cls('my_number', minvalue=3)
+ assert o.minvalue == 3
+ rule = o._rule_minvalue
+ translation = u'minvalue=%(minvalue)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in (4, 99, 1001):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in (-1, 0, 2):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(minvalue=3)
+ )
+ assert dummy.message == 'must be at least %(minvalue)d'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_rule_maxvalue(self):
+ """
+ Test the `ipalib.parameters.Int._rule_maxvalue` method.
+ """
+ o = self.cls('my_number', maxvalue=4)
+ assert o.maxvalue == 4
+ rule = o._rule_maxvalue
+ translation = u'maxvalue=%(maxvalue)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in (-1, 0, 4):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in (5, 99, 1009):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(maxvalue=4)
+ )
+ assert dummy.message == 'can be at most %(maxvalue)d'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_convert_scalar(self):
+ """
+ Test the `ipalib.parameters.Int._convert_scalar` method.
+ Assure radix prefixes work, str objects fail,
+ floats (native & string) are truncated,
+ large magnitude values are promoted to long,
+ empty strings & invalid numerical representations fail
+ """
+ o = self.cls('my_number')
+ # Assure invalid inputs raise error
+ for bad in ['hello', u'hello', True, None, u'', u'.']:
+ e = raises(errors.ConversionError, o._convert_scalar, bad)
+ assert e.name == 'my_number'
+ assert e.index is None
+ # Assure large magnatude values are handled correctly
+ assert type(o._convert_scalar(sys.maxint*2)) == long
+ assert o._convert_scalar(sys.maxint*2) == sys.maxint*2
+ assert o._convert_scalar(unicode(sys.maxint*2)) == sys.maxint*2
+ assert o._convert_scalar(long(16)) == 16
+ # Assure normal conversions produce expected result
+ assert o._convert_scalar(u'16.99') == 16
+ assert o._convert_scalar(16.99) == 16
+ assert o._convert_scalar(u'16') == 16
+ assert o._convert_scalar(u'0x10') == 16
+ assert o._convert_scalar(u'020') == 16
+
+class test_Decimal(ClassChecker):
+ """
+ Test the `ipalib.parameters.Decimal` class.
+ """
+ _cls = parameters.Decimal
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.Decimal.__init__` method.
+ """
+ # Test with no kwargs:
+ o = self.cls('my_number')
+ assert o.type is Decimal
+ assert isinstance(o, parameters.Decimal)
+ assert o.minvalue is None
+ assert o.maxvalue is None
+
+ # Test when min > max:
+ e = raises(ValueError, self.cls, 'my_number', minvalue=Decimal('22.5'), maxvalue=Decimal('15.1'))
+ assert str(e) == \
+ "Decimal('my_number'): minvalue > maxvalue (minvalue=22.5, maxvalue=15.1)"
+
+ def test_rule_minvalue(self):
+ """
+ Test the `ipalib.parameters.Decimal._rule_minvalue` method.
+ """
+ o = self.cls('my_number', minvalue='3.1')
+ assert o.minvalue == Decimal('3.1')
+ rule = o._rule_minvalue
+ translation = u'minvalue=%(minvalue)s'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in (Decimal('3.2'), Decimal('99.0')):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in (Decimal('-1.2'), Decimal('0.0'), Decimal('3.0')):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(minvalue=Decimal('3.1'))
+ )
+ assert dummy.message == 'must be at least %(minvalue)s'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_rule_maxvalue(self):
+ """
+ Test the `ipalib.parameters.Decimal._rule_maxvalue` method.
+ """
+ o = self.cls('my_number', maxvalue='4.7')
+ assert o.maxvalue == Decimal('4.7')
+ rule = o._rule_maxvalue
+ translation = u'maxvalue=%(maxvalue)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+
+ # Test with passing values:
+ for value in (Decimal('-1.0'), Decimal('0.1'), Decimal('4.2')):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # Test with failing values:
+ for value in (Decimal('5.3'), Decimal('99.9')):
+ assert_equal(
+ rule(dummy, value),
+ translation % dict(maxvalue=Decimal('4.7'))
+ )
+ assert dummy.message == 'can be at most %(maxvalue)s'
+ assert dummy.called() is True
+ dummy.reset()
+
+ def test_precision(self):
+ """
+ Test the `ipalib.parameters.Decimal` precision attribute
+ """
+ # precission is None
+ param = self.cls('my_number')
+
+ for value in (Decimal('0'), Decimal('4.4'), Decimal('4.67')):
+ assert_equal(
+ param(value),
+ value)
+
+ # precision is 0
+ param = self.cls('my_number', precision=0)
+ for original,expected in ((Decimal('0'), '0'),
+ (Decimal('1.1'), '1'),
+ (Decimal('4.67'), '5')):
+ assert_equal(
+ str(param(original)),
+ expected)
+
+ # precision is 1
+ param = self.cls('my_number', precision=1)
+ for original,expected in ((Decimal('0'), '0.0'),
+ (Decimal('1.1'), '1.1'),
+ (Decimal('4.67'), '4.7')):
+ assert_equal(
+ str(param(original)),
+ expected)
+
+ # value has too many digits
+ param = self.cls('my_number', precision=1)
+ e = raises(ConversionError, param, '123456789012345678901234567890')
+
+ assert str(e) == \
+ "invalid 'my_number': quantize result has too many digits for current context"
+
+ def test_exponential(self):
+ """
+ Test the `ipalib.parameters.Decimal` exponential attribute
+ """
+ param = self.cls('my_number', exponential=True)
+ for original,expected in ((Decimal('0'), '0'),
+ (Decimal('1E3'), '1E+3'),
+ (Decimal('3.4E2'), '3.4E+2')):
+ assert_equal(
+ str(param(original)),
+ expected)
+
+
+ param = self.cls('my_number', exponential=False)
+ for original,expected in ((Decimal('0'), '0'),
+ (Decimal('1E3'), '1000'),
+ (Decimal('3.4E2'), '340')):
+ assert_equal(
+ str(param(original)),
+ expected)
+
+ def test_numberclass(self):
+ """
+ Test the `ipalib.parameters.Decimal` numberclass attribute
+ """
+ # test default value: '-Normal', '+Zero', '+Normal'
+ param = self.cls('my_number')
+ for value,raises_verror in ((Decimal('0'), False),
+ (Decimal('-0'), True),
+ (Decimal('1E8'), False),
+ (Decimal('-1.1'), False),
+ (Decimal('-Infinity'), True),
+ (Decimal('+Infinity'), True),
+ (Decimal('NaN'), True)):
+ if raises_verror:
+ raises(ValidationError, param, value)
+ else:
+ param(value)
+
+
+ param = self.cls('my_number', exponential=True,
+ numberclass=('-Normal', '+Zero', '+Infinity'))
+ for value,raises_verror in ((Decimal('0'), False),
+ (Decimal('-0'), True),
+ (Decimal('1E8'), True),
+ (Decimal('-1.1'), False),
+ (Decimal('-Infinity'), True),
+ (Decimal('+Infinity'), False),
+ (Decimal('NaN'), True)):
+ if raises_verror:
+ raises(ValidationError, param, value)
+ else:
+ param(value)
+
+class test_AccessTime(ClassChecker):
+ """
+ Test the `ipalib.parameters.AccessTime` class.
+ """
+ _cls = parameters.AccessTime
+
+ def test_init(self):
+ """
+ Test the `ipalib.parameters.AccessTime.__init__` method.
+ """
+ # Test with no kwargs:
+ o = self.cls('my_time')
+ assert o.type is unicode
+ assert isinstance(o, parameters.AccessTime)
+ assert o.multivalue is False
+ translation = u'length=%(length)r'
+ dummy = dummy_ugettext(translation)
+ assert dummy.translation is translation
+ rule = o._rule_required
+
+ # Check some good rules
+ for value in (u'absolute 201012161032 ~ 201012161033',
+ u'periodic monthly week 2 day Sat,Sun 0900-1300',
+ u'periodic yearly month 4 day 1-31 0800-1400',
+ u'periodic weekly day 7 0800-1400',
+ u'periodic daily 0800-1400',
+ ):
+ assert rule(dummy, value) is None
+ assert dummy.called() is False
+
+ # And some bad ones
+ for value in (u'absolute 201012161032 - 201012161033',
+ u'absolute 201012161032 ~',
+ u'periodic monthly day Sat,Sun 0900-1300',
+ u'periodical yearly month 4 day 1-31 0800-1400',
+ u'periodic weekly day 8 0800-1400',
+ ):
+ e = raises(ValidationError, o._rule_required, None, value)
+
+def test_create_param():
+ """
+ Test the `ipalib.parameters.create_param` function.
+ """
+ f = parameters.create_param
+
+ # Test that Param instances are returned unchanged:
+ params = (
+ parameters.Param('one?'),
+ parameters.Int('two+'),
+ parameters.Str('three*'),
+ parameters.Bytes('four'),
+ )
+ for p in params:
+ assert f(p) is p
+
+ # Test that the spec creates an Str instance:
+ for spec in ('one?', 'two+', 'three*', 'four'):
+ (name, kw) = parameters.parse_param_spec(spec)
+ p = f(spec)
+ assert p.param_spec is spec
+ assert p.name == name
+ assert p.required is kw['required']
+ assert p.multivalue is kw['multivalue']
+
+ # Test that TypeError is raised when spec is neither a Param nor a str:
+ for spec in (u'one', 42, parameters.Param, parameters.Str):
+ e = raises(TypeError, f, spec)
+ assert str(e) == \
+ TYPE_ERROR % ('spec', (str, parameters.Param), spec, type(spec))
+
+
+def test_messages():
+ """
+ Test module level message in `ipalib.parameters`.
+ """
+ for name in dir(parameters):
+ if name.startswith('_'):
+ continue
+ attr = getattr(parameters, name)
+ if not (isclass(attr) and issubclass(attr, parameters.Param)):
+ continue
+ assert type(attr.type_error) is str
+ assert attr.type_error in parameters.__messages
+
+
+class test_IA5Str(ClassChecker):
+ """
+ Test the `ipalib.parameters.IA5Str` class.
+ """
+ _cls = parameters.IA5Str
+
+ def test_convert_scalar(self):
+ """
+ Test the `ipalib.parameters.IA5Str._convert_scalar` method.
+ """
+ o = self.cls('my_str')
+ mthd = o._convert_scalar
+ for value in (u'Hello', 42, 1.2):
+ assert mthd(value) == unicode(value)
+ bad = ['HelloĆ”']
+ for value in bad:
+ e = raises(errors.ConversionError, mthd, value)
+ assert e.name == 'my_str'
+ assert e.index is None
+ assert_equal(e.error, "The character '\\xc3' is not allowed.")