diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_ipalib/test_frontend.py | 519 | ||||
-rw-r--r-- | tests/test_ipalib/test_ipa_types.py | 430 | ||||
-rw-r--r-- | tests/test_ipalib/test_parameter.py | 531 | ||||
-rw-r--r-- | tests/test_ipalib/test_parameters.py | 944 | ||||
-rw-r--r-- | tests/util.py | 23 |
5 files changed, 1005 insertions, 1442 deletions
diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 94e586fe..071a70fd 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -23,7 +23,9 @@ Test the `ipalib.frontend` module. from tests.util import raises, getitem, no_set, no_del, read_only from tests.util import check_TypeError, ClassChecker, create_test_api -from ipalib import frontend, backend, plugable, errors, ipa_types, config +from tests.util import assert_equal +from ipalib.constants import TYPE_ERROR +from ipalib import frontend, backend, plugable, errors2, errors, parameters, config def test_RULE_FLAG(): @@ -70,420 +72,6 @@ def test_is_rule(): assert not is_rule(call(None)) -class test_DefaultFrom(ClassChecker): - """ - Test the `ipalib.frontend.DefaultFrom` class. - """ - _cls = frontend.DefaultFrom - - def test_class(self): - """ - Test the `ipalib.frontend.DefaultFrom` class. - """ - assert self.cls.__bases__ == (plugable.ReadOnly,) - - def test_init(self): - """ - Test the `ipalib.frontend.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') - - def test_call(self): - """ - Test the `ipalib.frontend.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.frontend.parse_param_spec` function. - """ - f = frontend.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)) - - -class test_Param(ClassChecker): - """ - Test the `ipalib.frontend.Param` class. - """ - _cls = frontend.Param - - def test_class(self): - """ - Test the `ipalib.frontend.Param` class. - """ - assert self.cls.__bases__ == (plugable.ReadOnly,) - - def test_init(self): - """ - Test the `ipalib.frontend.Param.__init__` method. - """ - name = 'sn' - o = self.cls(name) - assert o.__islocked__() is True - - # Test default values - assert read_only(o, 'name') is name - assert read_only(o, 'cli_name') is name - assert isinstance(read_only(o, 'type'), ipa_types.Unicode) - assert read_only(o, 'doc') == '' - assert read_only(o, 'required') is True - assert read_only(o, 'multivalue') is False - assert read_only(o, 'default') is None - assert read_only(o, 'default_from') is None - assert read_only(o, 'flags') == frozenset() - assert read_only(o, 'rules') == tuple() - assert len(read_only(o, 'all_rules')) == 1 - assert read_only(o, 'primary_key') is False - - # Test all kw args: - t = ipa_types.Int() - assert self.cls(name, cli_name='last').cli_name == 'last' - assert self.cls(name, type=t).type is t - assert self.cls(name, doc='the doc').doc == 'the doc' - assert self.cls(name, required=False).required is False - assert self.cls(name, multivalue=True).multivalue is True - assert self.cls(name, default=u'Hello').default == u'Hello' - df = frontend.DefaultFrom(lambda f, l: f + l, - 'first', 'last', - ) - lam = lambda first, last: first + last - for cb in (df, lam): - o = self.cls(name, default_from=cb) - assert type(o.default_from) is frontend.DefaultFrom - assert o.default_from.keys == ('first', 'last') - assert o.default_from.callback('butt', 'erfly') == 'butterfly' - assert self.cls(name, flags=('one', 'two', 'three')).flags == \ - frozenset(['one', 'two', 'three']) - rules = (lambda whatever: 'Not okay!',) - o = self.cls(name, rules=rules) - assert o.rules is rules - assert o.all_rules[1:] == rules - assert self.cls(name, primary_key=True).primary_key is True - - # Test default type_: - o = self.cls(name) - assert isinstance(o.type, ipa_types.Unicode) - - # Test param spec parsing: - o = self.cls('name?') - assert o.name == 'name' - assert o.required is False - assert o.multivalue is False - - o = self.cls('name*') - assert o.name == 'name' - assert o.required is False - assert o.multivalue is True - - o = self.cls('name+') - assert o.name == 'name' - assert o.required is True - assert o.multivalue is True - - e = raises(TypeError, self.cls, name, whatever=True, another=False) - assert str(e) == \ - 'Param.__init__() takes no such kwargs: another, whatever' - - def test_ispassword(self): - """ - Test the `ipalib.frontend.Param.ispassword` method. - """ - name = 'userpassword' - okay = 'password' - nope = ['', 'pass', 'word', 'passwd'] - for flag in nope: - o = self.cls(name, flags=[flag]) - assert o.ispassword() is False - o = self.cls(name, flags=[flag, okay]) - assert o.ispassword() is True - assert self.cls(name).ispassword() is False - assert self.cls(name, flags=[okay]).ispassword() is True - assert self.cls(name, flags=[okay]+nope).ispassword() is True - - def test_clone(self): - """ - Test the `ipalib.frontend.Param.__clone__` method. - """ - def compare(o, kw): - for (k, v) in kw.iteritems(): - assert getattr(o, k) == v, (k, v, getattr(o, k)) - default = dict( - required=False, - multivalue=False, - default=None, - default_from=None, - rules=tuple(), - ) - name = 'hair_color?' - type_ = ipa_types.Int() - o = self.cls(name, type=type_) - compare(o, default) - - override = dict(multivalue=True, default=42) - d = dict(default) - d.update(override) - clone = o.__clone__(**override) - assert clone.name == 'hair_color' - assert clone.type is o.type - compare(clone, d) - - def test_convert(self): - """ - Test the `ipalib.frontend.Param.convert` method. - """ - name = 'some_number' - type_ = ipa_types.Int() - okay = (7, 7L, 7.0, ' 7 ') - fail = ('7.0', '7L', 'whatever', object) - none = (None, '', u'', tuple(), []) - - # Scenario 1: multivalue=False - o = self.cls(name, type=type_) - for n in none: - assert o.convert(n) is None - for value in okay: - new = o.convert(value) - assert new == 7 - assert type(new) is int - for value in fail: - e = raises(errors.ConversionError, o.convert, value) - assert e.name is name - assert e.value is value - assert e.error is type_.conversion_error - assert e.index is None - - # Scenario 2: multivalue=True - o = self.cls(name, type=type_, multivalue=True) - for n in none: - assert o.convert(n) is None - for value in okay: - assert o.convert((value,)) == (7,) - assert o.convert([value]) == (7,) - assert o.convert(okay) == tuple(int(v) for v in okay) - cnt = 5 - for value in fail: - for i in xrange(cnt): - others = list(7 for x in xrange(cnt)) - others[i] = value - for v in [tuple(others), list(others)]: - e = raises(errors.ConversionError, o.convert, v) - assert e.name is name - assert e.value is value - assert e.error is type_.conversion_error - assert e.index == i - - def test_normalize(self): - """ - Test the `ipalib.frontend.Param.normalize` method. - """ - name = 'sn' - callback = lambda value: value.lower() - values = (None, u'Hello', (u'Hello',), 'hello', ['hello']) - none = (None, '', u'', tuple(), []) - - # Scenario 1: multivalue=False, normalize=None - o = self.cls(name) - for v in values: - # When normalize=None, value is returned, no type checking: - assert o.normalize(v) is v - - # Scenario 2: multivalue=False, normalize=callback - o = self.cls(name, normalize=callback) - for v in (u'Hello', u'hello', 'Hello'): # Okay - assert o.normalize(v) == 'hello' - for v in [None, 42, (u'Hello',)]: # Not basestring - assert o.normalize(v) is v - for n in none: - assert o.normalize(n) is None - - # Scenario 3: multivalue=True, normalize=None - o = self.cls(name, multivalue=True) - for v in values: - # When normalize=None, value is returned, no type checking: - assert o.normalize(v) is v - - # Scenario 4: multivalue=True, normalize=callback - o = self.cls(name, multivalue=True, normalize=callback) - assert o.normalize([]) is None - assert o.normalize(tuple()) is None - for value in [(u'Hello',), (u'hello',), 'Hello', ['Hello']]: # Okay - assert o.normalize(value) == (u'hello',) - fail = 42 # Not basestring - for v in [[fail], (u'hello', fail)]: # Non basestring member - assert o.normalize(v) == tuple(v) - for n in none: - assert o.normalize(n) is None - - def test_validate(self): - """ - Test the `ipalib.frontend.Param.validate` method. - """ - name = 'sn' - type_ = ipa_types.Unicode() - def case_rule(value): - if not value.islower(): - return 'Must be lower case' - my_rules = (case_rule,) - okay = u'whatever' - fail_case = u'Whatever' - fail_type = 'whatever' - - # Scenario 1: multivalue=False - o = self.cls(name, type=type_, rules=my_rules) - assert o.rules == my_rules - assert o.all_rules == (type_.validate, case_rule) - o.validate(okay) - e = raises(errors.RuleError, o.validate, fail_case) - assert e.name is name - assert e.value is fail_case - assert e.error == 'Must be lower case' - assert e.rule is case_rule - assert e.index is None - check_TypeError(fail_type, unicode, 'value', o.validate, fail_type) - - ## Scenario 2: multivalue=True - o = self.cls(name, type=type_, multivalue=True, rules=my_rules) - o.validate((okay,)) - cnt = 5 - for i in xrange(cnt): - others = list(okay for x in xrange(cnt)) - others[i] = fail_case - value = tuple(others) - e = raises(errors.RuleError, o.validate, value) - assert e.name is name - assert e.value is fail_case - assert e.error == 'Must be lower case' - assert e.rule is case_rule - assert e.index == i - for not_tuple in (okay, [okay]): - check_TypeError(not_tuple, tuple, 'value', o.validate, not_tuple) - for has_str in [(fail_type,), (okay, fail_type)]: - check_TypeError(fail_type, unicode, 'value', o.validate, has_str) - - def test_get_default(self): - """ - Test the `ipalib.frontend.Param.get_default` method. - """ - name = 'greeting' - default = u'Hello, world!' - default_from = frontend.DefaultFrom( - lambda first, last: u'Hello, %s %s!' % (first, last), - 'first', 'last' - ) - - # Scenario 1: multivalue=False - o = self.cls(name, - default=default, - default_from=default_from, - ) - assert o.default is default - assert o.default_from is default_from - assert o.get_default() == default - assert o.get_default(first='John', last='Doe') == 'Hello, John Doe!' - - # Scenario 2: multivalue=True - default = (default,) - o = self.cls(name, - default=default, - default_from=default_from, - multivalue=True, - ) - assert o.default is default - assert o.default_from is default_from - assert o.get_default() == default - assert o.get_default(first='John', last='Doe') == ('Hello, John Doe!',) - - def test_get_value(self): - """ - Test the `ipalib.frontend.Param.get_values` method. - """ - name = 'status' - values = (u'Active', u'Inactive') - o = self.cls(name, type=ipa_types.Unicode()) - assert o.get_values() == tuple() - o = self.cls(name, type=ipa_types.Enum(*values)) - assert o.get_values() == values - - def test_repr(self): - """ - Test the `ipalib.frontend.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_create_param(): - """ - Test the `ipalib.frontend.create_param` function. - """ - f = frontend.create_param - for name in ['arg', 'arg?', 'arg*', 'arg+']: - o = f(name) - assert type(o) is frontend.Param - assert type(o.type) is ipa_types.Unicode - assert o.name == 'arg' - assert f(o) is o - o = f('arg') - assert o.required is True - assert o.multivalue is False - o = f('arg?') - assert o.required is False - assert o.multivalue is False - o = f('arg*') - assert o.required is False - assert o.multivalue is True - o = f('arg+') - assert o.required is True - assert o.multivalue is True - - class test_Command(ClassChecker): """ Test the `ipalib.frontend.Command` class. @@ -499,28 +87,25 @@ class test_Command(ClassChecker): def __init__(self, name): self.name = name - def __call__(self, value): + def __call__(self, _, value): if value != self.name: - return 'must equal %s' % self.name + return _('must equal %r') % self.name - default_from = frontend.DefaultFrom( + default_from = parameters.DefaultFrom( lambda arg: arg, 'default_from' ) - normalize = lambda value: value.lower() + normalizer = lambda value: value.lower() class example(self.cls): takes_options = ( - frontend.Param('option0', - normalize=normalize, + parameters.Str('option0', Rule('option0'), + normalizer=normalizer, default_from=default_from, - rules=(Rule('option0'),) ), - frontend.Param('option1', - normalize=normalize, + parameters.Str('option1', Rule('option1'), + normalizer=normalizer, default_from=default_from, - rules=(Rule('option1'),), - required=True, ), ) return example @@ -577,8 +162,8 @@ class test_Command(ClassChecker): assert type(ns) is plugable.NameSpace assert len(ns) == len(args) assert list(ns) == ['destination', 'source'] - assert type(ns.destination) is frontend.Param - assert type(ns.source) is frontend.Param + assert type(ns.destination) is parameters.Str + assert type(ns.source) is parameters.Str assert ns.destination.required is True assert ns.destination.multivalue is False assert ns.source.required is False @@ -586,8 +171,8 @@ class test_Command(ClassChecker): # Test TypeError: e = raises(TypeError, self.get_instance, args=(u'whatever',)) - assert str(e) == \ - 'create_param() takes %r or %r; got %r' % (str, frontend.Param, u'whatever') + assert str(e) == TYPE_ERROR % ( + 'spec', (str, parameters.Param), u'whatever', unicode) # Test ValueError, required after optional: e = raises(ValueError, self.get_instance, args=('arg1?', 'arg2')) @@ -627,8 +212,8 @@ class test_Command(ClassChecker): assert type(ns) is plugable.NameSpace assert len(ns) == len(options) assert list(ns) == ['target', 'files'] - assert type(ns.target) is frontend.Param - assert type(ns.files) is frontend.Param + assert type(ns.target) is parameters.Str + assert type(ns.files) is parameters.Str assert ns.target.required is True assert ns.target.multivalue is False assert ns.files.required is False @@ -640,17 +225,13 @@ class test_Command(ClassChecker): """ assert 'convert' in self.cls.__public__ # Public kw = dict( - option0='option0', - option1='option1', + option0=u'1.5', + option1=u'7', ) - expected = dict(kw) - expected.update(dict(option0=u'option0', option1=u'option1')) o = self.subcls() o.finalize() for (key, value) in o.convert(**kw).iteritems(): - v = expected[key] - assert value == v - assert type(value) is type(v) + assert_equal(unicode(kw[key]), value) def test_normalize(self): """ @@ -671,22 +252,7 @@ class test_Command(ClassChecker): Test the `ipalib.frontend.Command.get_default` method. """ assert 'get_default' in self.cls.__public__ # Public - no_fill = dict( - option0='value0', - option1='value1', - whatever='hello world', - ) - fill = dict( - default_from='the default', - ) - default = dict( - option0='the default', - option1='the default', - ) - sub = self.subcls() - sub.finalize() - assert sub.get_default(**no_fill) == {} - assert sub.get_default(**fill) == default + # FIXME: Add an updated unit tests for get_default() def test_validate(self): """ @@ -697,7 +263,7 @@ class test_Command(ClassChecker): sub = self.subcls() sub.finalize() - # Check with valid args + # Check with valid values okay = dict( option0=u'option0', option1=u'option1', @@ -705,13 +271,13 @@ class test_Command(ClassChecker): ) sub.validate(**okay) - # Check with an invalid arg + # Check with an invalid value fail = dict(okay) fail['option0'] = u'whatever' - e = raises(errors.RuleError, sub.validate, **fail) - assert e.name == 'option0' - assert e.value == u'whatever' - assert e.error == 'must equal option0' + e = raises(errors2.ValidationError, sub.validate, **fail) + assert_equal(e.name, 'option0') + assert_equal(e.value, u'whatever') + assert_equal(e.error, u"must equal 'option0'") assert e.rule.__class__.__name__ == 'Rule' assert e.index is None @@ -845,9 +411,9 @@ class test_LocalOrRemote(ClassChecker): api.finalize() cmd = api.Command.example assert cmd() == ('execute', (None,), dict(server=False)) - assert cmd('var') == ('execute', (u'var',), dict(server=False)) + assert cmd(u'var') == ('execute', (u'var',), dict(server=False)) assert cmd(server=True) == ('forward', (None,), dict(server=True)) - assert cmd('var', server=True) == \ + assert cmd(u'var', server=True) == \ ('forward', (u'var',), dict(server=True)) # Test when in_server=True (should always call execute): @@ -856,9 +422,9 @@ class test_LocalOrRemote(ClassChecker): api.finalize() cmd = api.Command.example assert cmd() == ('execute', (None,), dict(server=False)) - assert cmd('var') == ('execute', (u'var',), dict(server=False)) + assert cmd(u'var') == ('execute', (u'var',), dict(server=False)) assert cmd(server=True) == ('execute', (None,), dict(server=True)) - assert cmd('var', server=True) == \ + assert cmd(u'var', server=True) == \ ('execute', (u'var',), dict(server=True)) @@ -974,7 +540,7 @@ class test_Object(ClassChecker): assert len(ns) == 2, repr(ns) assert list(ns) == ['banana', 'apple'] for p in ns(): - assert type(p) is frontend.Param + assert type(p) is parameters.Str assert p.required is True assert p.multivalue is False @@ -1001,15 +567,13 @@ class test_Object(ClassChecker): takes_params = ( 'one', 'two', - frontend.Param('three', - primary_key=True, - ), + parameters.Str('three', primary_key=True), 'four', ) o = example2() o.set_api(api) pk = o.primary_key - assert isinstance(pk, frontend.Param) + assert type(pk) is parameters.Str assert pk.name == 'three' assert pk.primary_key is True assert o.params[2] is o.primary_key @@ -1019,10 +583,10 @@ class test_Object(ClassChecker): # Test with multiple primary_key: class example3(self.cls): takes_params = ( - frontend.Param('one', primary_key=True), - frontend.Param('two', primary_key=True), + parameters.Str('one', primary_key=True), + parameters.Str('two', primary_key=True), 'three', - frontend.Param('four', primary_key=True), + parameters.Str('four', primary_key=True), ) o = example3() e = raises(ValueError, o.set_api, api) @@ -1155,12 +719,7 @@ class test_Property(ClassChecker): Test the `ipalib.frontend.Property` class. """ assert self.cls.__bases__ == (frontend.Attribute,) - assert isinstance(self.cls.type, ipa_types.Unicode) - assert self.cls.required is False - assert self.cls.multivalue is False - assert self.cls.default is None - assert self.cls.default_from is None - assert self.cls.normalize is None + assert self.cls.klass is parameters.Str def test_init(self): """ @@ -1170,7 +729,7 @@ class test_Property(ClassChecker): assert len(o.rules) == 1 assert o.rules[0].__name__ == 'rule0_lowercase' param = o.param - assert isinstance(param, frontend.Param) + assert isinstance(param, parameters.Str) assert param.name == 'givenname' assert param.doc == 'User first name' diff --git a/tests/test_ipalib/test_ipa_types.py b/tests/test_ipalib/test_ipa_types.py deleted file mode 100644 index eb166069..00000000 --- a/tests/test_ipalib/test_ipa_types.py +++ /dev/null @@ -1,430 +0,0 @@ -# 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; version 2 only -# -# 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, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" -Test the `ipalib.ipa_types` module. -""" - -from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker -from ipalib import ipa_types, errors, plugable - - -def test_check_min_max(): - """ - Test the `ipalib.ipa_types.check_min_max` function. - """ - f = ipa_types.check_min_max - okay = [ - (None, -5), - (-20, None), - (-20, -5), - ] - for (l, h) in okay: - assert f(l, h, 'low', 'high') is None - fail_type = [ - '10', - 10.0, - 10L, - True, - False, - object, - ] - for value in fail_type: - e = raises(TypeError, f, value, None, 'low', 'high') - assert str(e) == 'low must be an int or None, got: %r' % value - e = raises(TypeError, f, None, value, 'low', 'high') - assert str(e) == 'high must be an int or None, got: %r' % value - fail_value = [ - (10, 5), - (-5, -10), - (5, -10), - ] - for (l, h) in fail_value: - e = raises(ValueError, f, l, h, 'low', 'high') - assert str(e) == 'low > high: low=%r, high=%r' % (l, h) - - -class test_Type(ClassChecker): - """ - Test the `ipalib.ipa_types.Type` class. - """ - _cls = ipa_types.Type - - def test_class(self): - """ - Test the `ipalib.ipa_types.Type` class. - """ - assert self.cls.__bases__ == (plugable.ReadOnly,) - - def test_init(self): - """ - Test the `ipalib.ipa_types.Type.__init__` method. - """ - okay = (bool, int, float, unicode) - for t in okay: - o = self.cls(t) - assert o.__islocked__() is True - assert read_only(o, 'type') is t - assert read_only(o, 'name') is 'Type' - - type_errors = (None, True, 8, 8.0, u'hello') - for t in type_errors: - e = raises(TypeError, self.cls, t) - assert str(e) == '%r is not %r' % (type(t), type) - - value_errors = (long, complex, str, tuple, list, dict, set, frozenset) - for t in value_errors: - e = raises(ValueError, self.cls, t) - assert str(e) == 'not an allowed type: %r' % t - - def test_validate(self): - """ - Test the `ipalib.ipa_types.Type.validate` method. - """ - o = self.cls(unicode) - for value in (None, u'Hello', 'Hello', 42, False): - assert o.validate(value) is None - - -class test_Bool(ClassChecker): - """ - Test the `ipalib.ipa_types.Bool` class. - """ - _cls = ipa_types.Bool - - def test_class(self): - """ - Test the `ipalib.ipa_types.Bool` class. - """ - assert self.cls.__bases__ == (ipa_types.Type,) - - def test_init(self): - """ - Test the `ipalib.ipa_types.Bool.__init__` method. - """ - o = self.cls() - assert o.__islocked__() is True - assert read_only(o, 'type') is bool - assert read_only(o, 'name') == 'Bool' - assert read_only(o, 'true') == 'Yes' - assert read_only(o, 'false') == 'No' - - keys = ('true', 'false') - val = 'some value' - for key in keys: - # Check that kwarg sets appropriate attribute: - o = self.cls(**{key: val}) - assert read_only(o, key) is val - # Check that None raises TypeError: - e = raises(TypeError, self.cls, **{key: None}) - assert str(e) == '`%s` cannot be None' % key - - # Check that ValueError is raise if true == false: - e = raises(ValueError, self.cls, true=1L, false=1.0) - assert str(e) == 'cannot be equal: true=1L, false=1.0' - - def test_call(self): - """ - Test the `ipalib.ipa_types.Bool.__call__` method. - """ - o = self.cls() - assert o(True) is True - assert o('Yes') is True - assert o(False) is False - assert o('No') is False - for value in (0, 1, 'True', 'False', 'yes', 'no'): - # value is not be converted, so None is returned - assert o(value) is None - - -class test_Int(ClassChecker): - """ - Test the `ipalib.ipa_types.Int` class. - """ - _cls = ipa_types.Int - - def test_class(self): - """ - Test the `ipalib.ipa_types.Int` class. - """ - assert self.cls.__bases__ == (ipa_types.Type,) - - def test_init(self): - """ - Test the `ipalib.ipa_types.Int.__init__` method. - """ - o = self.cls() - assert o.__islocked__() is True - assert read_only(o, 'type') is int - assert read_only(o, 'name') == 'Int' - assert read_only(o, 'min_value') is None - assert read_only(o, 'max_value') is None - - okay = [ - (None, -5), - (-20, None), - (-20, -5), - ] - for (l, h) in okay: - o = self.cls(min_value=l, max_value=h) - assert o.min_value is l - assert o.max_value is h - - fail_type = [ - '10', - 10.0, - 10L, - True, - False, - object, - ] - for value in fail_type: - e = raises(TypeError, self.cls, min_value=value) - assert str(e) == ( - 'min_value must be an int or None, got: %r' % value - ) - e = raises(TypeError, self.cls, max_value=value) - assert str(e) == ( - 'max_value must be an int or None, got: %r' % value - ) - - fail_value = [ - (10, 5), - (5, -5), - (-5, -10), - ] - for (l, h) in fail_value: - e = raises(ValueError, self.cls, min_value=l, max_value=h) - assert str(e) == ( - 'min_value > max_value: min_value=%d, max_value=%d' % (l, h) - ) - - def test_call(self): - """ - Test the `ipalib.ipa_types.Int.__call__` method. - """ - o = self.cls() - - # Test calling with None - e = raises(TypeError, o, None) - assert str(e) == 'value cannot be None' - - # Test with values that can be converted: - okay = [ - 3, - '3', - ' 3 ', - 3L, - 3.0, - ] - for value in okay: - assert o(value) == 3 - - # Test with values that cannot be converted: - fail = [ - object, - '3.0', - '3L', - 'whatever', - ] - for value in fail: - assert o(value) is None - - def test_validate(self): - """ - Test the `ipalib.ipa_types.Int.validate` method. - """ - o = self.cls(min_value=2, max_value=7) - assert o.validate(2) is None - assert o.validate(5) is None - assert o.validate(7) is None - assert o.validate(1) == 'Cannot be smaller than 2' - assert o.validate(8) == 'Cannot be larger than 7' - for val in ['5', 5.0, 5L, None, True, False, object]: - assert o.validate(val) == 'Must be an integer' - - -class test_Unicode(ClassChecker): - """ - Test the `ipalib.ipa_types.Unicode` class. - """ - _cls = ipa_types.Unicode - - def test_class(self): - """ - Test the `ipalib.ipa_types.Unicode` class. - """ - assert self.cls.__bases__ == (ipa_types.Type,) - - def test_init(self): - """ - Test the `ipalib.ipa_types.Unicode.__init__` method. - """ - o = self.cls() - assert o.__islocked__() is True - assert read_only(o, 'type') is unicode - assert read_only(o, 'name') == 'Unicode' - assert read_only(o, 'min_length') is None - assert read_only(o, 'max_length') is None - assert read_only(o, 'pattern') is None - assert read_only(o, 'regex') is None - - # Test min_length, max_length: - okay = ( - (0, 1), - (8, 8), - ) - for (l, h) in okay: - o = self.cls(min_length=l, max_length=h) - assert o.min_length == l - assert o.max_length == h - - fail_type = [ - '10', - 10.0, - 10L, - True, - False, - object, - ] - for value in fail_type: - e = raises(TypeError, self.cls, min_length=value) - assert str(e) == ( - 'min_length must be an int or None, got: %r' % value - ) - e = raises(TypeError, self.cls, max_length=value) - assert str(e) == ( - 'max_length must be an int or None, got: %r' % value - ) - - fail_value = [ - (10, 5), - (5, -5), - (0, -10), - ] - for (l, h) in fail_value: - e = raises(ValueError, self.cls, min_length=l, max_length=h) - assert str(e) == ( - 'min_length > max_length: min_length=%d, max_length=%d' % (l, h) - ) - - for (key, lower) in [('min_length', 0), ('max_length', 1)]: - value = lower - 1 - kw = {key: value} - e = raises(ValueError, self.cls, **kw) - assert str(e) == '%s must be >= %d, got: %d' % (key, lower, value) - - # Test pattern: - okay = [ - '(hello|world)', - u'(take the blue pill|take the red pill)', - ] - for value in okay: - o = self.cls(pattern=value) - assert o.pattern is value - assert o.regex is not None - - fail = [ - 42, - True, - False, - object, - ] - for value in fail: - e = raises(TypeError, self.cls, pattern=value) - assert str(e) == ( - 'pattern must be a basestring or None, got: %r' % value - ) - - # Test regex: - pat = '^(hello|world)$' - o = self.cls(pattern=pat) - for value in ('hello', 'world'): - m = o.regex.match(value) - assert m.group(1) == value - for value in ('hello beautiful', 'world!'): - assert o.regex.match(value) is None - - def test_validate(self): - """ - Test the `ipalib.ipa_types.Unicode.validate` method. - """ - pat = '^a_*b$' - o = self.cls(min_length=3, max_length=4, pattern=pat) - assert o.validate(u'a_b') is None - assert o.validate(u'a__b') is None - assert o.validate('a_b') == 'Must be a string' - assert o.validate(u'ab') == 'Must be at least 3 characters long' - assert o.validate(u'a___b') == 'Can be at most 4 characters long' - assert o.validate(u'a-b') == 'Must match %r' % pat - assert o.validate(u'a--b') == 'Must match %r' % pat - - -class test_Enum(ClassChecker): - """ - Test the `ipalib.ipa_types.Enum` class. - """ - _cls = ipa_types.Enum - - def test_class(self): - """ - Test the `ipalib.ipa_types.Enum` class. - """ - assert self.cls.__bases__ == (ipa_types.Type,) - - def test_init(self): - """ - Test the `ipalib.ipa_types.Enum.__init__` method. - """ - for t in (unicode, int, float): - values = (t(1), t(2), t(3)) - o = self.cls(*values) - assert o.__islocked__() is True - assert read_only(o, 'type') is t - assert read_only(o, 'name') is 'Enum' - assert read_only(o, 'values') == values - assert read_only(o, 'frozenset') == frozenset(values) - - # Check that ValueError is raised when no values are given: - e = raises(ValueError, self.cls) - assert str(e) == 'Enum requires at least one value' - - # Check that TypeError is raised when type of first value is not - # allowed: - e = raises(TypeError, self.cls, 'hello') - assert str(e) == '%r: %r not unicode, int, nor float' % ('hello', str) - #self.cls('hello') - - # Check that TypeError is raised when subsequent values aren't same - # type as first: - e = raises(TypeError, self.cls, u'hello', 'world') - assert str(e) == '%r: %r is not %r' % ('world', str, unicode) - - def test_validate(self): - """ - Test the `ipalib.ipa_types.Enum.validate` method. - """ - values = (u'hello', u'naughty', u'nurse') - o = self.cls(*values) - for value in values: - assert o.validate(value) is None - assert o.validate(str(value)) == 'Incorrect type' - for value in (u'one fish', u'two fish'): - assert o.validate(value) == 'Invalid value' - assert o.validate(str(value)) == 'Incorrect type' diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py deleted file mode 100644 index e2016f06..00000000 --- a/tests/test_ipalib/test_parameter.py +++ /dev/null @@ -1,531 +0,0 @@ -# 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; version 2 only -# -# 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, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" -Test the `ipalib.parameter` module. -""" - -from tests.util import raises, ClassChecker, read_only -from tests.util import dummy_ugettext, assert_equal -from tests.data import binary_bytes, utf8_bytes, unicode_str -from ipalib import parameter, request -from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR, NULLS - - -class test_DefaultFrom(ClassChecker): - """ - Test the `ipalib.parameter.DefaultFrom` class. - """ - _cls = parameter.DefaultFrom - - def test_init(self): - """ - Test the `ipalib.parameter.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) - - def test_call(self): - """ - Test the `ipalib.parameter.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.parameter.parse_param_spec` function. - """ - f = parameter.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) - - # Test that ValueError is raised if len(spec) < 2: - e = raises(ValueError, f, 'n') - assert str(e) == "spec must be at least 2 characters; got 'n'" - - -class test_Param(ClassChecker): - """ - Test the `ipalib.parameter.Param` class. - """ - _cls = parameter.Param - - def test_init(self): - """ - Test the `ipalib.parameter.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.__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 is None - assert o.doc == '' - 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.flags == frozenset() - - # 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'" - - def test_repr(self): - """ - Test the `ipalib.parameter.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_get_label(self): - """ - Test the `ipalib.parameter.get_label` method. - """ - context = request.context - cli_name = 'the_cli_name' - message = 'The Label' - label = lambda _: _(message) - o = self.cls('name', cli_name=cli_name, label=label) - assert o.label is label - - ## Scenario 1: label=callable (a lambda form) - - # Test with no context.ugettext: - assert not hasattr(context, 'ugettext') - assert_equal(o.get_label(), u'The Label') - - # Test with dummy context.ugettext: - assert not hasattr(context, 'ugettext') - dummy = dummy_ugettext() - context.ugettext = dummy - assert o.get_label() is dummy.translation - assert dummy.message is message - del context.ugettext - - ## Scenario 2: label=None - o = self.cls('name', cli_name=cli_name) - assert o.label is None - - # Test with no context.ugettext: - assert not hasattr(context, 'ugettext') - assert_equal(o.get_label(), u'the_cli_name') - - # Test with dummy context.ugettext: - assert not hasattr(context, 'ugettext') - dummy = dummy_ugettext() - context.ugettext = dummy - assert_equal(o.get_label(), u'the_cli_name') - assert not hasattr(dummy, 'message') - - # Cleanup - del context.ugettext - assert not hasattr(context, 'ugettext') - - def test_convert(self): - """ - Test the `ipalib.parameter.Param.convert` method. - """ - okay = ('Hello', u'Hello', 0, 4.2, True, False) - 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 - 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.parameter.Param._convert_scalar` method. - """ - o = self.cls('my_param') - e = raises(NotImplementedError, o._convert_scalar, 'some value') - assert str(e) == 'Param._convert_scalar()' - class Subclass(self.cls): - pass - o = Subclass('my_param') - e = raises(NotImplementedError, o._convert_scalar, 'some value') - assert str(e) == 'Subclass._convert_scalar()' - - -class test_Bytes(ClassChecker): - """ - Test the `ipalib.parameter.Bytes` class. - """ - _cls = parameter.Bytes - - def test_init(self): - """ - Test the `ipalib.parameter.Bytes.__init__` method. - """ - o = self.cls('my_bytes') - assert o.type is str - 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_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.parameter.Bytes._rule_minlength` method. - """ - name = 'My Bytes' - o = self.cls('my_bytes', minlength=3) - assert o.minlength == 3 - m = o._rule_minlength - translation = u'name=%(name)r, minlength=%(minlength)r' - dummy = dummy_ugettext(translation) - assert dummy.translation is translation - - # Test with passing values: - for value in ('abc', 'four', '12345'): - assert m(dummy, name, value) is None - assert not hasattr(dummy, 'message') - - # Test with a failing value: - assert_equal( - m(dummy, name, 'ab'), - translation % dict(name=name, minlength=3), - ) - assert dummy.message == \ - '%(name)s must be at least %(minlength)d bytes' - - def test_rule_maxlength(self): - """ - Test the `ipalib.parameter.Bytes._rule_maxlength` method. - """ - name = 'My Bytes' - o = self.cls('my_bytes', maxlength=4) - assert o.maxlength == 4 - m = o._rule_maxlength - translation = u'name=%(name)r, maxlength=%(maxlength)r' - dummy = dummy_ugettext(translation) - assert dummy.translation is translation - - # Test with passing values: - for value in ('ab', '123', 'four'): - assert m(dummy, name, value) is None - assert not hasattr(dummy, 'message') - - # Test with a failing value: - assert_equal( - m(dummy, name, '12345'), - translation % dict(name=name, maxlength=4), - ) - assert dummy.message == \ - '%(name)s can be at most %(maxlength)d bytes' - - def test_rule_length(self): - """ - Test the `ipalib.parameter.Bytes._rule_length` method. - """ - name = 'My Bytes' - o = self.cls('my_bytes', length=4) - assert o.length == 4 - m = o._rule_length - translation = u'name=%(name)r, length=%(length)r' - dummy = dummy_ugettext(translation) - assert dummy.translation is translation - - # Test with passing values: - for value in ('1234', 'four'): - assert m(dummy, name, value) is None - assert not hasattr(dummy, 'message') - - # Test with failing values: - for value in ('ab', '123', '12345', 'abcdef'): - assert_equal( - m(dummy, name, value), - translation % dict(name=name, length=4), - ) - assert dummy.message == \ - '%(name)s must be exactly %(length)d bytes' - dummy = dummy_ugettext(translation) - - -class test_Str(ClassChecker): - """ - Test the `ipalib.parameter.Str` class. - """ - _cls = parameter.Str - - def test_init(self): - """ - Test the `ipalib.parameter.Str.__init__` method. - """ - o = self.cls('my_str') - 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 - - def test_convert_scalar(self): - """ - Test the `ipalib.parameter.Str._convert_scalar` method. - """ - o = self.cls('my_str') - for value in (u'Hello', 42, 1.2, True): - assert o._convert_scalar(value) == unicode(value) - for value in ('Hello', (None,), [u'42', '42'], dict(hello=u'world')): - e = raises(TypeError, o._convert_scalar, value) - assert str(e) == \ - 'Can only implicitly convert int, float, or bool; got %r' % value - - def test_rule_minlength(self): - """ - Test the `ipalib.parameter.Str._rule_minlength` method. - """ - name = 'My Str' - o = self.cls('my_str', minlength=3) - assert o.minlength == 3 - m = o._rule_minlength - translation = u'name=%(name)r, 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 m(dummy, name, value) is None - assert not hasattr(dummy, 'message') - - # Test with a failing value: - assert_equal( - m(dummy, name, u'ab'), - translation % dict(name=name, minlength=3), - ) - assert dummy.message == \ - '%(name)s must be at least %(minlength)d characters' - - def test_rule_maxlength(self): - """ - Test the `ipalib.parameter.Str._rule_maxlength` method. - """ - name = 'My Str' - o = self.cls('my_str', maxlength=4) - assert o.maxlength == 4 - m = o._rule_maxlength - translation = u'name=%(name)r, 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 m(dummy, name, value) is None - assert not hasattr(dummy, 'message') - - # Test with a failing value: - assert_equal( - m(dummy, name, u'12345'), - translation % dict(name=name, maxlength=4), - ) - assert dummy.message == \ - '%(name)s can be at most %(maxlength)d characters' - - def test_rule_length(self): - """ - Test the `ipalib.parameter.Str._rule_length` method. - """ - name = 'My Str' - o = self.cls('my_str', length=4) - assert o.length == 4 - m = o._rule_length - translation = u'name=%(name)r, length=%(length)r' - dummy = dummy_ugettext(translation) - assert dummy.translation is translation - - # Test with passing values: - for value in (u'1234', u'four'): - assert m(dummy, name, value) is None - assert not hasattr(dummy, 'message') - - # Test with failing values: - for value in (u'ab', u'123', u'12345', u'abcdef'): - assert_equal( - m(dummy, name, value), - translation % dict(name=name, length=4), - ) - assert dummy.message == \ - '%(name)s must be exactly %(length)d characters' - dummy = dummy_ugettext(translation) diff --git a/tests/test_ipalib/test_parameters.py b/tests/test_ipalib/test_parameters.py new file mode 100644 index 00000000..f9e370fe --- /dev/null +++ b/tests/test_ipalib/test_parameters.py @@ -0,0 +1,944 @@ +# 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Test the `ipalib.parameters` module. +""" + +from types import NoneType +from inspect import isclass +from tests.util import raises, ClassChecker, read_only +from tests.util import dummy_ugettext, assert_equal +from tests.data import binary_bytes, utf8_bytes, unicode_str +from ipalib import parameters, request, errors2 +from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR, NULLS + + +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) + + 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) + + # Test that ValueError is raised if len(spec) < 2: + e = raises(ValueError, f, 'n') + assert str(e) == "spec must be at least 2 characters; got 'n'" + + +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.__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 is None + assert o.doc == '' + 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.create_default is None + assert o._get_default is None + assert o.autofill is False + assert o.query is False + assert o.flags == frozenset() + + # 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 default_from and + # create_default: + e = raises(ValueError, self.cls, 'my_param', + default_from=lambda first, last: first[0] + last, + create_default=lambda **kw: 'The Default' + ) + assert str(e) == '%s: cannot have both %r and %r' % ( + "Param('my_param')", 'default_from', 'create_default', + ) + + # Test that _get_default gets set: + call1 = lambda first, last: first[0] + last + call2 = lambda **kw: 'The Default' + o = self.cls('my_param', default_from=call1) + assert o.default_from.callback is call1 + assert o._get_default is o.default_from + o = self.cls('my_param', create_default=call2) + assert o.create_default is call2 + assert o._get_default is call2 + + 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_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_get_label(self): + """ + Test the `ipalib.parameters.get_label` method. + """ + context = request.context + cli_name = 'the_cli_name' + message = 'The Label' + label = lambda _: _(message) + o = self.cls('name', cli_name=cli_name, label=label) + assert o.label is label + + ## Scenario 1: label=callable (a lambda form) + + # Test with no context.ugettext: + assert not hasattr(context, 'ugettext') + assert_equal(o.get_label(), u'The Label') + + # Test with dummy context.ugettext: + assert not hasattr(context, 'ugettext') + dummy = dummy_ugettext() + context.ugettext = dummy + assert o.get_label() is dummy.translation + assert dummy.message is message + del context.ugettext + + ## Scenario 2: label=None + o = self.cls('name', cli_name=cli_name) + assert o.label is None + + # Test with no context.ugettext: + assert not hasattr(context, 'ugettext') + assert_equal(o.get_label(), u'the_cli_name') + + # Test with dummy context.ugettext: + assert not hasattr(context, 'ugettext') + dummy = dummy_ugettext() + context.ugettext = dummy + assert_equal(o.get_label(), u'the_cli_name') + assert not hasattr(dummy, 'message') + + # Cleanup + del context.ugettext + assert not hasattr(context, 'ugettext') + + def test_convert(self): + """ + Test the `ipalib.parameters.Param.convert` method. + """ + okay = ('Hello', u'Hello', 0, 4.2, True, False) + 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 + 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(errors2.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(errors2.RequirementError, o.validate, None) + assert e.name == 'my_param' + + # Test with required=False + o = self.cls('my_param', required=False) + assert o.required is False + assert o.validate(None) is None + + # Test with query=True: + o = self.cls('my_param', query=True) + assert o.query is True + assert o.validate(None) is None + + # Test with multivalue=True: + o = self.cls('my_param', multivalue=True) + e = raises(TypeError, o.validate, []) + assert str(e) == TYPE_ERROR % ('value', tuple, [], list) + e = raises(ValueError, o.validate, tuple()) + 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)) + assert str(e) == TYPE_ERROR % ('value[2]', NoneType, 42, int) + o = self.cls('my_param') + e = raises(TypeError, o.validate, 'Hello') + assert str(e) == TYPE_ERROR % ('value', 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) is None + assert pass1.calls == [(request.ugettext, 11)] + assert pass2.calls == [(request.ugettext, 11)] + pass1.reset() + pass2.reset() + o = Example('example', pass1, pass2, fail) + e = raises(errors2.ValidationError, o.validate, 42) + assert e.name == 'example' + assert e.error == u'no good' + assert e.index is None + assert pass1.calls == [(request.ugettext, 42)] + assert pass2.calls == [(request.ugettext, 42)] + assert fail.calls == [(request.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)) is None + assert pass1.calls == [ + (request.ugettext, 3), + (request.ugettext, 9), + ] + assert pass2.calls == [ + (request.ugettext, 3), + (request.ugettext, 9), + ] + pass1.reset() + pass2.reset() + o = Example('multi_example', pass1, pass2, fail, multivalue=True) + assert o.multivalue is True + e = raises(errors2.ValidationError, o.validate, (3, 9)) + assert e.name == 'multi_example' + assert e.error == u'this one is not good' + assert e.index == 0 + assert pass1.calls == [(request.ugettext, 3)] + assert pass2.calls == [(request.ugettext, 3)] + assert fail.calls == [(request.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 % ('value', bool, 0, int) + e = raises(TypeError, o._validate_scalar, 'Hi', index=4) + assert str(e) == TYPE_ERROR % ('value[4]', 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 == [ + (request.ugettext, True), + (request.ugettext, False), + ] + + # Test with a failing rule: + okay = DummyRule() + fail = DummyRule(u'this describes the error') + o = MyParam('my_param', okay, fail) + e = raises(errors2.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(errors2.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 == [ + (request.ugettext, True), + (request.ugettext, False), + ] + assert fail.calls == [ + (request.ugettext, True), + (request.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 + + # Test with create_default: + o = Str('my_str', + normalizer=PassThrough(), + default=u'Static Default', + create_default=lambda **kw: u'The created default', + ) + default = o.get_default(first=u'john', last='doe') + assert_equal(default, u'The created default') + 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.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 not hasattr(o, 'pattern') + + # 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.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_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() + + +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.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): + assert mthd(value) == unicode(value) + for value in [True, 'Hello', (u'Hello',), [42.3], dict(one=1)]: + e = raises(errors2.ConversionError, mthd, value) + assert e.name == 'my_str' + assert e.index is None + assert_equal(e.error, u'must be Unicode text') + e = raises(errors2.ConversionError, mthd, value, index=18) + assert e.name == 'my_str' + assert e.index == 18 + assert_equal(e.error, u'must be Unicode text') + + 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_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 diff --git a/tests/util.py b/tests/util.py index 3033b82b..af4c2393 100644 --- a/tests/util.py +++ b/tests/util.py @@ -28,6 +28,7 @@ import tempfile import shutil import ipalib from ipalib.plugable import Plugin +from ipalib.request import context @@ -202,6 +203,14 @@ class ClassChecker(object): 'get_subcls()' ) + def tearDown(self): + """ + nose tear-down fixture. + """ + for name in ('ugettext', 'ungettext'): + if hasattr(context, name): + delattr(context, name) + @@ -297,12 +306,24 @@ class dummy_ugettext(object): assert type(self.translation) is unicode def __call__(self, message): - assert type(message) is str assert self.__called is False self.__called = True + assert type(message) is str + assert not hasattr(self, 'message') self.message = message + assert type(self.translation) is unicode return self.translation + def called(self): + return self.__called + + def reset(self): + assert type(self.translation) is unicode + assert type(self.message) is str + del self.message + assert self.__called is True + self.__called = False + class dummy_ungettext(object): __called = False |