From 7721443a625b2efd0744ad347c62795e5ba6bb91 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 20:41:15 -0600 Subject: Moved ipalib/tests/ into tests/test_ipalib/ --- tests/test_ipalib/__init__.py | 22 + tests/test_ipalib/test_backend.py | 37 ++ tests/test_ipalib/test_cli.py | 138 +++++ tests/test_ipalib/test_config.py | 101 ++++ tests/test_ipalib/test_crud.py | 168 ++++++ tests/test_ipalib/test_errors.py | 274 +++++++++ tests/test_ipalib/test_frontend.py | 1080 +++++++++++++++++++++++++++++++++++ tests/test_ipalib/test_ipa_types.py | 371 ++++++++++++ tests/test_ipalib/test_plugable.py | 896 +++++++++++++++++++++++++++++ tests/test_ipalib/test_tstutil.py | 148 +++++ tests/test_ipalib/test_util.py | 49 ++ tests/test_ipalib/tstutil.py | 147 +++++ 12 files changed, 3431 insertions(+) create mode 100644 tests/test_ipalib/__init__.py create mode 100644 tests/test_ipalib/test_backend.py create mode 100644 tests/test_ipalib/test_cli.py create mode 100644 tests/test_ipalib/test_config.py create mode 100644 tests/test_ipalib/test_crud.py create mode 100644 tests/test_ipalib/test_errors.py create mode 100644 tests/test_ipalib/test_frontend.py create mode 100644 tests/test_ipalib/test_ipa_types.py create mode 100644 tests/test_ipalib/test_plugable.py create mode 100644 tests/test_ipalib/test_tstutil.py create mode 100644 tests/test_ipalib/test_util.py create mode 100644 tests/test_ipalib/tstutil.py (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/__init__.py b/tests/test_ipalib/__init__.py new file mode 100644 index 00000000..d3658c45 --- /dev/null +++ b/tests/test_ipalib/__init__.py @@ -0,0 +1,22 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib` package. +""" diff --git a/tests/test_ipalib/test_backend.py b/tests/test_ipalib/test_backend.py new file mode 100644 index 00000000..967e9fdf --- /dev/null +++ b/tests/test_ipalib/test_backend.py @@ -0,0 +1,37 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib.backend` module. +""" + +from ipalib import backend, plugable, errors +from tstutil import ClassChecker + + +class test_Backend(ClassChecker): + """ + Test the `backend.Backend` class. + """ + + _cls = backend.Backend + + def test_class(self): + assert self.cls.__bases__ == (plugable.Plugin,) + assert self.cls.__proxy__ is False diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py new file mode 100644 index 00000000..90c66d41 --- /dev/null +++ b/tests/test_ipalib/test_cli.py @@ -0,0 +1,138 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib.cli` module. +""" + +from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker +from ipalib import cli, plugable + + +def test_to_cli(): + """ + Tests the `cli.to_cli` function. + """ + f = cli.to_cli + assert f('initialize') == 'initialize' + assert f('user_add') == 'user-add' + + +def test_from_cli(): + """ + Tests the `cli.from_cli` function. + """ + f = cli.from_cli + assert f('initialize') == 'initialize' + assert f('user-add') == 'user_add' + + +def get_cmd_name(i): + return 'cmd_%d' % i + +class DummyCommand(object): + def __init__(self, name): + self.__name = name + + def __get_name(self): + return self.__name + name = property(__get_name) + +class DummyAPI(object): + def __init__(self, cnt): + self.__cmd = plugable.NameSpace(self.__cmd_iter(cnt)) + + def __get_cmd(self): + return self.__cmd + Command = property(__get_cmd) + + def __cmd_iter(self, cnt): + for i in xrange(cnt): + yield DummyCommand(get_cmd_name(i)) + + def finalize(self): + pass + + def register(self, *args, **kw): + pass + + + + + +class test_CLI(ClassChecker): + """ + Tests the `cli.CLI` class. + """ + _cls = cli.CLI + + def test_class(self): + assert type(self.cls.api) is property + + def test_api(self): + """ + Tests the `cli.CLI.api` property. + """ + api = 'the plugable.API instance' + o = self.cls(api) + assert read_only(o, 'api') is api + + def dont_parse(self): + """ + Tests the `cli.CLI.parse` method. + """ + o = self.cls(None) + args = ['hello', 'naughty', 'nurse'] + kw = dict( + first_name='Naughty', + last_name='Nurse', + ) + opts = ['--%s=%s' % (k.replace('_', '-'), v) for (k, v) in kw.items()] + assert o.parse(args + []) == (args, {}) + assert o.parse(opts + []) == ([], kw) + assert o.parse(args + opts) == (args, kw) + assert o.parse(opts + args) == (args, kw) + + def test_mcl(self): + """ + Tests the `cli.CLI.mcl` (Max Command Length) property . + """ + cnt = 100 + api = DummyAPI(cnt) + len(api.Command) == cnt + o = self.cls(api) + assert o.mcl is None + o.build_map() + assert o.mcl == 6 # len('cmd_99') + + def test_dict(self): + """ + Tests the `cli.CLI.__contains__` and `cli.CLI.__getitem__` methods. + """ + cnt = 25 + api = DummyAPI(cnt) + assert len(api.Command) == cnt + o = self.cls(api) + o.build_map() + for cmd in api.Command(): + key = cli.to_cli(cmd.name) + assert key in o + assert o[key] is cmd + assert cmd.name not in o + raises(KeyError, getitem, o, cmd.name) diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py new file mode 100644 index 00000000..de7d4c22 --- /dev/null +++ b/tests/test_ipalib/test_config.py @@ -0,0 +1,101 @@ +# Authors: +# Martin Nagy +# +# 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 + +""" +Unit tests for `ipalib.config` module. +""" + +import types + +from tstutil import raises +from ipalib import config + + +def test_generate_env(): + """ + Test the `config.generate_env` function + """ + + # Make sure we don't overwrite any properties + env = dict( + query_dns = False, + server = ('first', 'second'), + realm = 'myrealm', + ) + d = config.generate_env(env) + assert d['query_dns'] == False + + # Make sure the servers is overwrote properly (that it is still LazyProp) + iter = d['server'].get_value() + assert iter.next() == 'first' + assert iter.next() == 'second' + + +def test_LazyProp(): + """ + Test the `config.LazyProp` class + """ + + def dummy(): + return 1 + + # Basic sanity testing with no initial value + prop = config.LazyProp(dummy) + assert prop.get_value() == 1 + prop.set_value(2) + assert prop.get_value() == 2 + + # Basic sanity testing with initial value + prop = config.LazyProp(dummy, 3) + assert prop.get_value() == 3 + prop.set_value(4) + assert prop.get_value() == 4 + + +def test_LazyIter(): + """ + Test the `config.LazyIter` class + """ + + def dummy(): + yield 1 + yield 2 + + # Basic sanity testing with no initial value + prop = config.LazyIter(dummy) + iter = prop.get_value() + assert iter.next() == 1 + assert iter.next() == 2 + raises(StopIteration, iter.next) + + # Basic sanity testing with initial value + prop = config.LazyIter(dummy, 0) + iter = prop.get_value() + assert iter.next() == 0 + assert iter.next() == 1 + assert iter.next() == 2 + raises(StopIteration, iter.next) + + +def test_read_config(): + """ + Test the `config.read_config` class + """ + + raises(AssertionError, config.read_config, 1) diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py new file mode 100644 index 00000000..9355f237 --- /dev/null +++ b/tests/test_ipalib/test_crud.py @@ -0,0 +1,168 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib.crud` module. +""" + +from tstutil import read_only, raises, ClassChecker +from ipalib import crud, frontend, plugable, config + +def get_api(): + api = plugable.API( + frontend.Object, + frontend.Method, + frontend.Property, + ) + api.env.update(config.generate_env()) + class user(frontend.Object): + takes_params = ( + 'givenname', + 'sn', + frontend.Param('uid', primary_key=True), + 'initials', + ) + api.register(user) + return api + + +class test_Add(ClassChecker): + """ + Test the `crud.Add` class. + """ + + _cls = crud.Add + + def test_class(self): + assert self.cls.__bases__ == (frontend.Method,) + + def test_options_args(self): + """ + Test `crud.Add.get_args` and `crud.Add.get_options` methods. + """ + api = get_api() + class user_add(self.cls): + pass + api.register(user_add) + api.finalize() + assert list(api.Method.user_add.args) == ['uid'] + assert list(api.Method.user_add.options) == \ + ['givenname', 'sn', 'initials'] + for param in api.Method.user_add.options(): + assert param.required is True + + +class test_Get(ClassChecker): + """ + Test the `crud.Get` class. + """ + + _cls = crud.Get + + def test_class(self): + assert self.cls.__bases__ == (frontend.Method,) + + def test_options_args(self): + """ + Test `crud.Get.get_args` and `crud.Get.get_options` methods. + """ + api = get_api() + class user_get(self.cls): + pass + api.register(user_get) + api.finalize() + assert list(api.Method.user_get.args) == ['uid'] + assert list(api.Method.user_get.options) == [] + + +class test_Del(ClassChecker): + """ + Test the `crud.Del` class. + """ + + _cls = crud.Del + + def test_class(self): + assert self.cls.__bases__ == (frontend.Method,) + + def test_options_args(self): + """ + Test `crud.Del.get_args` and `crud.Del.get_options` methods. + """ + api = get_api() + class user_del(self.cls): + pass + api.register(user_del) + api.finalize() + assert list(api.Method.user_del.args) == ['uid'] + assert list(api.Method.user_del.options) == [] + + +class test_Mod(ClassChecker): + """ + Test the `crud.Mod` class. + """ + + _cls = crud.Mod + + def test_class(self): + assert self.cls.__bases__ == (frontend.Method,) + + def test_options_args(self): + """ + Test `crud.Mod.get_args` and `crud.Mod.get_options` methods. + """ + api = get_api() + class user_mod(self.cls): + pass + api.register(user_mod) + api.finalize() + assert list(api.Method.user_mod.args) == ['uid'] + assert api.Method.user_mod.args[0].required is True + assert list(api.Method.user_mod.options) == \ + ['givenname', 'sn', 'initials'] + for param in api.Method.user_mod.options(): + assert param.required is False + + +class test_Find(ClassChecker): + """ + Test the `crud.Find` class. + """ + + _cls = crud.Find + + def test_class(self): + assert self.cls.__bases__ == (frontend.Method,) + + def test_options_args(self): + """ + Test `crud.Find.get_args` and `crud.Find.get_options` methods. + """ + api = get_api() + class user_find(self.cls): + pass + api.register(user_find) + api.finalize() + assert list(api.Method.user_find.args) == ['uid'] + assert api.Method.user_find.args[0].required is True + assert list(api.Method.user_find.options) == \ + ['givenname', 'sn', 'initials'] + for param in api.Method.user_find.options(): + assert param.required is False diff --git a/tests/test_ipalib/test_errors.py b/tests/test_ipalib/test_errors.py new file mode 100644 index 00000000..7d2df4df --- /dev/null +++ b/tests/test_ipalib/test_errors.py @@ -0,0 +1,274 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib.errors` module. +""" + +from tstutil import raises, ClassChecker +from ipalib import errors + + +type_format = '%s: need a %r; got %r' + + +def check_TypeError(f, value, type_, name, **kw): + e = raises(TypeError, f, value, type_, name, **kw) + assert e.value is value + assert e.type is type_ + assert e.name is name + assert str(e) == type_format % (name, type_, value) + + +def test_raise_TypeError(): + """ + Tests the `errors.raise_TypeError` function. + """ + f = errors.raise_TypeError + value = 'Hello.' + type_ = unicode + name = 'message' + + check_TypeError(f, value, type_, name) + + # name not an str + fail_name = 42 + e = raises(AssertionError, f, value, type_, fail_name) + assert str(e) == type_format % ('name', str, fail_name), str(e) + + # type_ not a type: + fail_type = unicode() + e = raises(AssertionError, f, value, fail_type, name) + assert str(e) == type_format % ('type_', type, fail_type) + + # type(value) is type_: + fail_value = u'How are you?' + e = raises(AssertionError, f, fail_value, type_, name) + assert str(e) == 'value: %r is a %r' % (fail_value, type_) + + +def test_check_type(): + """ + Tests the `errors.check_type` function. + """ + f = errors.check_type + value = 'How are you?' + type_ = str + name = 'greeting' + + # Should pass: + assert value is f(value, type_, name) + assert None is f(None, type_, name, allow_none=True) + + # Should raise TypeError + check_TypeError(f, None, type_, name) + check_TypeError(f, value, basestring, name) + check_TypeError(f, value, unicode, name) + + # name not an str + fail_name = unicode(name) + e = raises(AssertionError, f, value, type_, fail_name) + assert str(e) == type_format % ('name', str, fail_name) + + # type_ not a type: + fail_type = 42 + e = raises(AssertionError, f, value, fail_type, name) + assert str(e) == type_format % ('type_', type, fail_type) + + # allow_none not a bool: + fail_bool = 0 + e = raises(AssertionError, f, value, type_, name, allow_none=fail_bool) + assert str(e) == type_format % ('allow_none', bool, fail_bool) + + +def test_check_isinstance(): + """ + Tests the `errors.check_isinstance` function. + """ + f = errors.check_isinstance + value = 'How are you?' + type_ = str + name = 'greeting' + + # Should pass: + assert value is f(value, type_, name) + assert value is f(value, basestring, name) + assert None is f(None, type_, name, allow_none=True) + + # Should raise TypeError + check_TypeError(f, None, type_, name) + check_TypeError(f, value, unicode, name) + + # name not an str + fail_name = unicode(name) + e = raises(AssertionError, f, value, type_, fail_name) + assert str(e) == type_format % ('name', str, fail_name) + + # type_ not a type: + fail_type = 42 + e = raises(AssertionError, f, value, fail_type, name) + assert str(e) == type_format % ('type_', type, fail_type) + + # allow_none not a bool: + fail_bool = 0 + e = raises(AssertionError, f, value, type_, name, allow_none=fail_bool) + assert str(e) == type_format % ('allow_none', bool, fail_bool) + + +class test_IPAError(ClassChecker): + """ + Tests the `errors.IPAError` exception. + """ + _cls = errors.IPAError + + def test_class(self): + assert self.cls.__bases__ == (Exception,) + + def test_init(self): + """ + Tests the `errors.IPAError.__init__` method. + """ + args = ('one fish', 'two fish') + e = self.cls(*args) + assert e.args == args + assert self.cls().args == tuple() + + def test_str(self): + """ + Tests the `errors.IPAError.__str__` method. + """ + f = 'The %s color is %s.' + class custom_error(self.cls): + format = f + for args in [('sexiest', 'red'), ('most-batman-like', 'black')]: + e = custom_error(*args) + assert e.args == args + assert str(e) == f % args + + +class test_ValidationError(ClassChecker): + """ + Tests the `errors.ValidationError` exception. + """ + _cls = errors.ValidationError + + def test_class(self): + assert self.cls.__bases__ == (errors.IPAError,) + + def test_init(self): + """ + Tests the `errors.ValidationError.__init__` method. + """ + name = 'login' + value = 'Whatever' + error = 'Must be lowercase.' + for index in (None, 3): + e = self.cls(name, value, error, index=index) + assert e.name is name + assert e.value is value + assert e.error is error + assert e.index is index + assert str(e) == 'invalid %r value %r: %s' % (name, value, error) + # Check that index default is None: + assert self.cls(name, value, error).index is None + # Check non str name raises AssertionError: + raises(AssertionError, self.cls, unicode(name), value, error) + # Check non int index raises AssertionError: + raises(AssertionError, self.cls, name, value, error, index=5.0) + # Check negative index raises AssertionError: + raises(AssertionError, self.cls, name, value, error, index=-2) + + +class test_ConversionError(ClassChecker): + """ + Tests the `errors.ConversionError` exception. + """ + _cls = errors.ConversionError + + def test_class(self): + assert self.cls.__bases__ == (errors.ValidationError,) + + def test_init(self): + """ + Tests the `errors.ConversionError.__init__` method. + """ + name = 'some_arg' + value = '42.0' + class type_(object): + conversion_error = 'Not an integer' + for index in (None, 7): + e = self.cls(name, value, type_, index=index) + assert e.name is name + assert e.value is value + assert e.type is type_ + assert e.error is type_.conversion_error + assert e.index is index + assert str(e) == 'invalid %r value %r: %s' % (name, value, + type_.conversion_error) + # Check that index default is None: + assert self.cls(name, value, type_).index is None + + +class test_RuleError(ClassChecker): + """ + Tests the `errors.RuleError` exception. + """ + _cls = errors.RuleError + + def test_class(self): + assert self.cls.__bases__ == (errors.ValidationError,) + + def test_init(self): + """ + Tests the `errors.RuleError.__init__` method. + """ + name = 'whatever' + value = 'The smallest weird number.' + def my_rule(value): + return 'Value is bad.' + error = my_rule(value) + for index in (None, 42): + e = self.cls(name, value, error, my_rule, index=index) + assert e.name is name + assert e.value is value + assert e.error is error + assert e.rule is my_rule + # Check that index default is None: + assert self.cls(name, value, error, my_rule).index is None + + +class test_RequirementError(ClassChecker): + """ + Tests the `errors.RequirementError` exception. + """ + _cls = errors.RequirementError + + def test_class(self): + assert self.cls.__bases__ == (errors.ValidationError,) + + def test_init(self): + """ + Tests the `errors.RequirementError.__init__` method. + """ + name = 'givenname' + e = self.cls(name) + assert e.name is name + assert e.value is None + assert e.error == 'Required' + assert e.index is None diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py new file mode 100644 index 00000000..c70cc00d --- /dev/null +++ b/tests/test_ipalib/test_frontend.py @@ -0,0 +1,1080 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib.frontend` module. +""" + +from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker +from tstutil import check_TypeError +from ipalib import frontend, backend, plugable, errors, ipa_types, config + + +def test_RULE_FLAG(): + assert frontend.RULE_FLAG == 'validation_rule' + + +def test_rule(): + """ + Tests the `frontend.rule` function. + """ + flag = frontend.RULE_FLAG + rule = frontend.rule + def my_func(): + pass + assert not hasattr(my_func, flag) + rule(my_func) + assert getattr(my_func, flag) is True + @rule + def my_func2(): + pass + assert getattr(my_func2, flag) is True + + +def test_is_rule(): + """ + Tests the `frontend.is_rule` function. + """ + is_rule = frontend.is_rule + flag = frontend.RULE_FLAG + + class no_call(object): + def __init__(self, value): + if value is not None: + assert value in (True, False) + setattr(self, flag, value) + + class call(no_call): + def __call__(self): + pass + + assert is_rule(call(True)) + assert not is_rule(no_call(True)) + assert not is_rule(call(False)) + assert not is_rule(call(None)) + + +class test_DefaultFrom(ClassChecker): + """ + Tests the `frontend.DefaultFrom` class. + """ + _cls = frontend.DefaultFrom + + def test_class(self): + assert self.cls.__bases__ == (plugable.ReadOnly,) + + def test_init(self): + """ + Tests the `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): + """ + Tests the `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 + 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 + + +def test_parse_param_spec(): + """ + Test the `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 `frontend.Param` class. + """ + _cls = frontend.Param + + def test_class(self): + assert self.cls.__bases__ == (plugable.ReadOnly,) + + def test_init(self): + """ + Test the `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 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, '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, 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' + 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_clone(self): + """ + Test the `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 `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 `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): + """ + Tests the `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): + """ + Tests the `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): + """ + Tests the `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_create_param(): + """ + Test the `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): + """ + Tests the `frontend.Command` class. + """ + _cls = frontend.Command + + def get_subcls(self): + class Rule(object): + def __init__(self, name): + self.name = name + + def __call__(self, value): + if value != self.name: + return 'must equal %s' % self.name + + default_from = frontend.DefaultFrom( + lambda arg: arg, + 'default_from' + ) + normalize = lambda value: value.lower() + + class example(self.cls): + takes_options = ( + frontend.Param('option0', + normalize=normalize, + default_from=default_from, + rules=(Rule('option0'),) + ), + frontend.Param('option1', + normalize=normalize, + default_from=default_from, + rules=(Rule('option1'),), + required=True, + ), + ) + return example + + def get_instance(self, args=tuple(), options=tuple()): + """ + Helper method used to test args and options. + """ + class example(self.cls): + takes_args = args + takes_options = options + o = example() + o.finalize() + return o + + def test_class(self): + assert self.cls.__bases__ == (plugable.Plugin,) + assert self.cls.takes_options == tuple() + assert self.cls.takes_args == tuple() + + def test_get_args(self): + """ + Tests the `frontend.Command.get_args` method. + """ + assert list(self.cls().get_args()) == [] + args = ('login', 'stuff') + o = self.get_instance(args=args) + assert o.get_args() is args + + def test_get_options(self): + """ + Tests the `frontend.Command.get_options` method. + """ + assert list(self.cls().get_options()) == [] + options = ('verbose', 'debug') + o = self.get_instance(options=options) + assert o.get_options() is options + + def test_args(self): + """ + Tests the ``Command.args`` instance attribute. + """ + assert 'args' in self.cls.__public__ # Public + assert self.cls().args is None + o = self.cls() + o.finalize() + assert type(o.args) is plugable.NameSpace + assert len(o.args) == 0 + args = ('destination', 'source?') + ns = self.get_instance(args=args).args + 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 ns.destination.required is True + assert ns.destination.multivalue is False + assert ns.source.required is False + assert ns.source.multivalue is False + + # 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') + + # Test ValueError, required after optional: + e = raises(ValueError, self.get_instance, args=('arg1?', 'arg2')) + assert str(e) == 'arg2: required argument after optional' + + # Test ValueError, scalar after multivalue: + e = raises(ValueError, self.get_instance, args=('arg1+', 'arg2')) + assert str(e) == 'arg2: only final argument can be multivalue' + + def test_max_args(self): + """ + Test the ``Command.max_args`` instance attribute. + """ + o = self.get_instance() + assert o.max_args == 0 + o = self.get_instance(args=('one?',)) + assert o.max_args == 1 + o = self.get_instance(args=('one', 'two?')) + assert o.max_args == 2 + o = self.get_instance(args=('one', 'multi+',)) + assert o.max_args is None + o = self.get_instance(args=('one', 'multi*',)) + assert o.max_args is None + + def test_options(self): + """ + Tests the ``Command.options`` instance attribute. + """ + assert 'options' in self.cls.__public__ # Public + assert self.cls().options is None + o = self.cls() + o.finalize() + assert type(o.options) is plugable.NameSpace + assert len(o.options) == 0 + options = ('target', 'files*') + ns = self.get_instance(options=options).options + 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 ns.target.required is True + assert ns.target.multivalue is False + assert ns.files.required is False + assert ns.files.multivalue is True + + def test_convert(self): + """ + Tests the `frontend.Command.convert` method. + """ + assert 'convert' in self.cls.__public__ # Public + kw = dict( + option0='option0', + option1='option1', + ) + 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) + + def test_normalize(self): + """ + Tests the `frontend.Command.normalize` method. + """ + assert 'normalize' in self.cls.__public__ # Public + kw = dict( + option0=u'OPTION0', + option1=u'OPTION1', + ) + norm = dict((k, v.lower()) for (k, v) in kw.items()) + sub = self.subcls() + sub.finalize() + assert sub.normalize(**kw) == norm + + def test_get_default(self): + """ + Tests the `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 + + def test_validate(self): + """ + Tests the `frontend.Command.validate` method. + """ + assert 'validate' in self.cls.__public__ # Public + + sub = self.subcls() + sub.finalize() + + # Check with valid args + okay = dict( + option0=u'option0', + option1=u'option1', + another_option='some value', + ) + sub.validate(**okay) + + # Check with an invalid arg + 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' + assert e.rule.__class__.__name__ == 'Rule' + assert e.index is None + + # Check with a missing required arg + fail = dict(okay) + fail.pop('option1') + e = raises(errors.RequirementError, sub.validate, **fail) + assert e.name == 'option1' + assert e.value is None + assert e.index is None + + def test_execute(self): + """ + Tests the `frontend.Command.execute` method. + """ + assert 'execute' in self.cls.__public__ # Public + + def test_args_to_kw(self): + """ + Test the `frontend.Command.args_to_kw` method. + """ + assert 'args_to_kw' in self.cls.__public__ # Public + o = self.get_instance(args=('one', 'two?')) + assert o.args_to_kw(1) == dict(one=1) + assert o.args_to_kw(1, 2) == dict(one=1, two=2) + + o = self.get_instance(args=('one', 'two*')) + assert o.args_to_kw(1) == dict(one=1) + assert o.args_to_kw(1, 2) == dict(one=1, two=(2,)) + assert o.args_to_kw(1, 2, 3) == dict(one=1, two=(2, 3)) + + o = self.get_instance(args=('one', 'two+')) + assert o.args_to_kw(1) == dict(one=1) + assert o.args_to_kw(1, 2) == dict(one=1, two=(2,)) + assert o.args_to_kw(1, 2, 3) == dict(one=1, two=(2, 3)) + + o = self.get_instance() + e = raises(errors.ArgumentError, o.args_to_kw, 1) + assert str(e) == 'example takes no arguments' + + o = self.get_instance(args=('one?',)) + e = raises(errors.ArgumentError, o.args_to_kw, 1, 2) + assert str(e) == 'example takes at most 1 argument' + + o = self.get_instance(args=('one', 'two?')) + e = raises(errors.ArgumentError, o.args_to_kw, 1, 2, 3) + assert str(e) == 'example takes at most 2 arguments' + + def test_kw_to_args(self): + """ + Tests the `frontend.Command.kw_to_args` method. + """ + assert 'kw_to_args' in self.cls.__public__ # Public + o = self.get_instance(args=('one', 'two?')) + assert o.kw_to_args() == (None, None) + assert o.kw_to_args(whatever='hello') == (None, None) + assert o.kw_to_args(one='the one') == ('the one', None) + assert o.kw_to_args(two='the two') == (None, 'the two') + assert o.kw_to_args(whatever='hello', two='Two', one='One') == \ + ('One', 'Two') + + def test_run(self): + """ + Test the `frontend.Command.run` method. + """ + class my_cmd(self.cls): + def execute(self, *args, **kw): + return ('execute', args, kw) + + def forward(self, *args, **kw): + return ('forward', args, kw) + + args = ('Hello,', 'world,') + kw = dict(how_are='you', on_this='fine day?') + + # Test in server context: + api = plugable.API(self.cls) + api.env.update(dict(server_context=True)) + api.finalize() + o = my_cmd() + o.set_api(api) + assert o.run.im_func is self.cls.run.im_func + assert ('execute', args, kw) == o.run(*args, **kw) + assert o.run.im_func is my_cmd.execute.im_func + + # Test in non-server context + api = plugable.API(self.cls) + api.env.update(dict(server_context=False)) + api.finalize() + o = my_cmd() + o.set_api(api) + assert o.run.im_func is self.cls.run.im_func + assert ('forward', args, kw) == o.run(*args, **kw) + assert o.run.im_func is my_cmd.forward.im_func + + +class test_Object(ClassChecker): + """ + Test the `frontend.Object` class. + """ + _cls = frontend.Object + + def test_class(self): + assert self.cls.__bases__ == (plugable.Plugin,) + assert self.cls.backend is None + assert self.cls.methods is None + assert self.cls.properties is None + assert self.cls.params is None + assert self.cls.params_minus_pk is None + assert self.cls.takes_params == tuple() + + def test_init(self): + """ + Test the `frontend.Object.__init__` method. + """ + o = self.cls() + assert o.backend is None + assert o.methods is None + assert o.properties is None + assert o.params is None + assert o.params_minus_pk is None + assert o.properties is None + + def test_set_api(self): + """ + Test the `frontend.Object.set_api` method. + """ + # Setup for test: + class DummyAttribute(object): + def __init__(self, obj_name, attr_name, name=None): + self.obj_name = obj_name + self.attr_name = attr_name + if name is None: + self.name = '%s_%s' % (obj_name, attr_name) + else: + self.name = name + self.param = frontend.create_param(attr_name) + + def __clone__(self, attr_name): + return self.__class__( + self.obj_name, + self.attr_name, + getattr(self, attr_name) + ) + + def get_attributes(cnt, format): + for name in ['other', 'user', 'another']: + for i in xrange(cnt): + yield DummyAttribute(name, format % i) + + cnt = 10 + formats = dict( + methods='method_%d', + properties='property_%d', + ) + + + _d = dict( + Method=plugable.NameSpace( + get_attributes(cnt, formats['methods']) + ), + Property=plugable.NameSpace( + get_attributes(cnt, formats['properties']) + ), + ) + api = plugable.MagicDict(_d) + assert len(api.Method) == cnt * 3 + assert len(api.Property) == cnt * 3 + + class user(self.cls): + pass + + # Actually perform test: + o = user() + o.set_api(api) + assert read_only(o, 'api') is api + for name in ['methods', 'properties']: + namespace = getattr(o, name) + assert isinstance(namespace, plugable.NameSpace) + assert len(namespace) == cnt + f = formats[name] + for i in xrange(cnt): + attr_name = f % i + attr = namespace[attr_name] + assert isinstance(attr, DummyAttribute) + assert attr is getattr(namespace, attr_name) + assert attr.obj_name == 'user' + assert attr.attr_name == attr_name + assert attr.name == attr_name + + # Test params instance attribute + o = self.cls() + o.set_api(api) + ns = o.params + assert type(ns) is plugable.NameSpace + assert len(ns) == 0 + class example(self.cls): + takes_params = ('banana', 'apple') + o = example() + o.set_api(api) + ns = o.params + assert type(ns) is plugable.NameSpace + assert len(ns) == 2, repr(ns) + assert list(ns) == ['banana', 'apple'] + for p in ns(): + assert type(p) is frontend.Param + assert p.required is True + assert p.multivalue is False + + def test_primary_key(self): + """ + Test the `frontend.Object.primary_key` attribute. + """ + api = plugable.API( + frontend.Method, + frontend.Property, + ) + api.env.update(config.generate_env()) + api.finalize() + + # Test with no primary keys: + class example1(self.cls): + takes_params = ( + 'one', + 'two', + ) + o = example1() + o.set_api(api) + assert o.primary_key is None + assert o.params_minus_pk is None + + # Test with 1 primary key: + class example2(self.cls): + takes_params = ( + 'one', + 'two', + frontend.Param('three', + primary_key=True, + ), + 'four', + ) + o = example2() + o.set_api(api) + pk = o.primary_key + assert isinstance(pk, frontend.Param) + assert pk.name == 'three' + assert pk.primary_key is True + assert o.params[2] is o.primary_key + assert isinstance(o.params_minus_pk, plugable.NameSpace) + assert list(o.params_minus_pk) == ['one', 'two', 'four'] + + # Test with multiple primary_key: + class example3(self.cls): + takes_params = ( + frontend.Param('one', primary_key=True), + frontend.Param('two', primary_key=True), + 'three', + frontend.Param('four', primary_key=True), + ) + o = example3() + e = raises(ValueError, o.set_api, api) + assert str(e) == \ + 'example3 (Object) has multiple primary keys: one, two, four' + + def test_backend(self): + """ + Test the `frontend.Object.backend` attribute. + """ + api = plugable.API( + frontend.Object, + frontend.Method, + frontend.Property, + backend.Backend, + ) + api.env.update(config.generate_env()) + class ldap(backend.Backend): + whatever = 'It worked!' + api.register(ldap) + class user(frontend.Object): + backend_name = 'ldap' + api.register(user) + api.finalize() + b = api.Object.user.backend + assert isinstance(b, ldap) + assert b.whatever == 'It worked!' + + +class test_Attribute(ClassChecker): + """ + Tests the `frontend.Attribute` class. + """ + _cls = frontend.Attribute + + def test_class(self): + assert self.cls.__bases__ == (plugable.Plugin,) + assert type(self.cls.obj) is property + assert type(self.cls.obj_name) is property + assert type(self.cls.attr_name) is property + + def test_init(self): + """ + Tests the `frontend.Attribute.__init__` method. + """ + class user_add(self.cls): + pass + o = user_add() + assert read_only(o, 'obj') is None + assert read_only(o, 'obj_name') == 'user' + assert read_only(o, 'attr_name') == 'add' + + def test_set_api(self): + """ + Tests the `frontend.Attribute.set_api` method. + """ + user_obj = 'The user frontend.Object instance' + class api(object): + Object = dict(user=user_obj) + class user_add(self.cls): + pass + o = user_add() + assert read_only(o, 'api') is None + assert read_only(o, 'obj') is None + o.set_api(api) + assert read_only(o, 'api') is api + assert read_only(o, 'obj') is user_obj + + +class test_Method(ClassChecker): + """ + Test the `frontend.Method` class. + """ + _cls = frontend.Method + + def test_class(self): + assert self.cls.__bases__ == (frontend.Attribute, frontend.Command) + assert self.cls.implements(frontend.Command) + assert self.cls.implements(frontend.Attribute) + + def test_init(self): + """ + Test the `frontend.Method.__init__` method. + """ + class user_add(self.cls): + pass + o = user_add() + assert o.name == 'user_add' + assert o.obj_name == 'user' + assert o.attr_name == 'add' + assert frontend.Command.implemented_by(o) + assert frontend.Attribute.implemented_by(o) + + +class test_Property(ClassChecker): + """ + Tests the `frontend.Property` class. + """ + _cls = frontend.Property + + def get_subcls(self): + class user_givenname(self.cls): + 'User first name' + + @frontend.rule + def rule0_lowercase(self, value): + if not value.islower(): + return 'Must be lowercase' + return user_givenname + + def test_class(self): + 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 + + def test_init(self): + """ + Tests the `frontend.Property.__init__` method. + """ + o = self.subcls() + assert len(o.rules) == 1 + assert o.rules[0].__name__ == 'rule0_lowercase' + param = o.param + assert isinstance(param, frontend.Param) + assert param.name == 'givenname' + assert param.doc == 'User first name' + + +class test_Application(ClassChecker): + """ + Tests the `frontend.Application` class. + """ + _cls = frontend.Application + + def test_class(self): + assert self.cls.__bases__ == (frontend.Command,) + assert type(self.cls.application) is property + + def test_application(self): + """ + Tests the `frontend.Application.application` property. + """ + assert 'application' in self.cls.__public__ # Public + assert 'set_application' in self.cls.__public__ # Public + app = 'The external application' + class example(self.cls): + 'A subclass' + for o in (self.cls(), example()): + assert read_only(o, 'application') is None + e = raises(TypeError, o.set_application, None) + assert str(e) == ( + '%s.application cannot be None' % o.__class__.__name__ + ) + o.set_application(app) + assert read_only(o, 'application') is app + e = raises(AttributeError, o.set_application, app) + assert str(e) == ( + '%s.application can only be set once' % o.__class__.__name__ + ) + assert read_only(o, 'application') is app diff --git a/tests/test_ipalib/test_ipa_types.py b/tests/test_ipalib/test_ipa_types.py new file mode 100644 index 00000000..b8e996a7 --- /dev/null +++ b/tests/test_ipalib/test_ipa_types.py @@ -0,0 +1,371 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib.ipa_types` module. +""" + +from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker +from ipalib import ipa_types, errors, plugable + + +def test_check_min_max(): + """ + Tests the `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): + """ + Tests the `ipa_types.Type` class. + """ + _cls = ipa_types.Type + + def test_class(self): + assert self.cls.__bases__ == (plugable.ReadOnly,) + + def test_init(self): + 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): + o = self.cls(unicode) + for value in (None, u'Hello', 'Hello', 42, False): + assert o.validate(value) is None + + +class test_Bool(ClassChecker): + _cls = ipa_types.Bool + + def test_class(self): + assert self.cls.__bases__ == (ipa_types.Type,) + + def test_init(self): + 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): + 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): + _cls = ipa_types.Int + + def test_class(self): + assert self.cls.__bases__ == (ipa_types.Type,) + + def test_init(self): + 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): + 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): + 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): + _cls = ipa_types.Unicode + + def test_class(self): + assert self.cls.__bases__ == (ipa_types.Type,) + + def test_init(self): + 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): + 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): + _cls = ipa_types.Enum + + def test_class(self): + assert self.cls.__bases__ == (ipa_types.Type,) + + def test_init(self): + 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): + 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_plugable.py b/tests/test_ipalib/test_plugable.py new file mode 100644 index 00000000..fd3c3c88 --- /dev/null +++ b/tests/test_ipalib/test_plugable.py @@ -0,0 +1,896 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib.plugable` module. +""" + +from tstutil import raises, no_set, no_del, read_only +from tstutil import getitem, setitem, delitem +from tstutil import ClassChecker +from ipalib import plugable, errors + + +class test_ReadOnly(ClassChecker): + """ + Test the `plugable.ReadOnly` class + """ + _cls = plugable.ReadOnly + + def test_class(self): + assert self.cls.__bases__ == (object,) + assert callable(self.cls.__lock__) + assert callable(self.cls.__islocked__) + + def test_lock(self): + """ + Test the `plugable.ReadOnly.__lock__` method. + """ + o = self.cls() + assert o._ReadOnly__locked is False + o.__lock__() + assert o._ReadOnly__locked is True + e = raises(AssertionError, o.__lock__) # Can only be locked once + assert str(e) == '__lock__() can only be called once' + assert o._ReadOnly__locked is True # This should still be True + + def test_lock(self): + """ + Test the `plugable.ReadOnly.__islocked__` method. + """ + o = self.cls() + assert o.__islocked__() is False + o.__lock__() + assert o.__islocked__() is True + + def test_setattr(self): + """ + Test the `plugable.ReadOnly.__setattr__` method. + """ + o = self.cls() + o.attr1 = 'Hello, world!' + assert o.attr1 == 'Hello, world!' + o.__lock__() + for name in ('attr1', 'attr2'): + e = raises(AttributeError, setattr, o, name, 'whatever') + assert str(e) == 'read-only: cannot set ReadOnly.%s' % name + assert o.attr1 == 'Hello, world!' + + def test_delattr(self): + """ + Test the `plugable.ReadOnly.__delattr__` method. + """ + o = self.cls() + o.attr1 = 'Hello, world!' + o.attr2 = 'How are you?' + assert o.attr1 == 'Hello, world!' + assert o.attr2 == 'How are you?' + del o.attr1 + assert not hasattr(o, 'attr1') + o.__lock__() + e = raises(AttributeError, delattr, o, 'attr2') + assert str(e) == 'read-only: cannot del ReadOnly.attr2' + assert o.attr2 == 'How are you?' + + +def test_lock(): + """ + Tests the `plugable.lock` function. + """ + f = plugable.lock + + # Test on a ReadOnly instance: + o = plugable.ReadOnly() + assert not o.__islocked__() + assert f(o) is o + assert o.__islocked__() + + # Test on something not subclassed from ReadOnly: + class not_subclass(object): + def __lock__(self): + pass + def __islocked__(self): + return True + o = not_subclass() + raises(ValueError, f, o) + + # Test that it checks __islocked__(): + class subclass(plugable.ReadOnly): + def __islocked__(self): + return False + o = subclass() + raises(AssertionError, f, o) + + +class test_SetProxy(ClassChecker): + """ + Tests the `plugable.SetProxy` class. + """ + _cls = plugable.SetProxy + + def test_class(self): + assert self.cls.__bases__ == (plugable.ReadOnly,) + + def test_init(self): + okay = (set, frozenset, dict) + fail = (list, tuple) + for t in okay: + self.cls(t()) + raises(TypeError, self.cls, t) + for t in fail: + raises(TypeError, self.cls, t()) + raises(TypeError, self.cls, t) + + def test_SetProxy(self): + def get_key(i): + return 'key_%d' % i + + cnt = 10 + target = set() + proxy = self.cls(target) + for i in xrange(cnt): + key = get_key(i) + + # Check initial state + assert len(proxy) == len(target) + assert list(proxy) == sorted(target) + assert key not in proxy + assert key not in target + + # Add and test again + target.add(key) + assert len(proxy) == len(target) + assert list(proxy) == sorted(target) + assert key in proxy + assert key in target + + +class test_DictProxy(ClassChecker): + """ + Tests the `plugable.DictProxy` class. + """ + _cls = plugable.DictProxy + + def test_class(self): + assert self.cls.__bases__ == (plugable.SetProxy,) + + def test_init(self): + self.cls(dict()) + raises(TypeError, self.cls, dict) + fail = (set, frozenset, list, tuple) + for t in fail: + raises(TypeError, self.cls, t()) + raises(TypeError, self.cls, t) + + def test_DictProxy(self): + def get_kv(i): + return ( + 'key_%d' % i, + 'val_%d' % i, + ) + cnt = 10 + target = dict() + proxy = self.cls(target) + for i in xrange(cnt): + (key, val) = get_kv(i) + + # Check initial state + assert len(proxy) == len(target) + assert list(proxy) == sorted(target) + assert list(proxy()) == [target[k] for k in sorted(target)] + assert key not in proxy + raises(KeyError, getitem, proxy, key) + + # Add and test again + target[key] = val + assert len(proxy) == len(target) + assert list(proxy) == sorted(target) + assert list(proxy()) == [target[k] for k in sorted(target)] + + # Verify TypeError is raised trying to set/del via proxy + raises(TypeError, setitem, proxy, key, val) + raises(TypeError, delitem, proxy, key) + + +class test_MagicDict(ClassChecker): + """ + Tests the `plugable.MagicDict` class. + """ + _cls = plugable.MagicDict + + def test_class(self): + assert self.cls.__bases__ == (plugable.DictProxy,) + for non_dict in ('hello', 69, object): + raises(TypeError, self.cls, non_dict) + + def test_MagicDict(self): + cnt = 10 + keys = [] + d = dict() + dictproxy = self.cls(d) + for i in xrange(cnt): + key = 'key_%d' % i + val = 'val_%d' % i + keys.append(key) + + # Test thet key does not yet exist + assert len(dictproxy) == i + assert key not in dictproxy + assert not hasattr(dictproxy, key) + raises(KeyError, getitem, dictproxy, key) + raises(AttributeError, getattr, dictproxy, key) + + # Test that items/attributes cannot be set on dictproxy: + raises(TypeError, setitem, dictproxy, key, val) + raises(AttributeError, setattr, dictproxy, key, val) + + # Test that additions in d are reflected in dictproxy: + d[key] = val + assert len(dictproxy) == i + 1 + assert key in dictproxy + assert hasattr(dictproxy, key) + assert dictproxy[key] is val + assert read_only(dictproxy, key) is val + + # Test __iter__ + assert list(dictproxy) == keys + + for key in keys: + # Test that items cannot be deleted through dictproxy: + raises(TypeError, delitem, dictproxy, key) + raises(AttributeError, delattr, dictproxy, key) + + # Test that deletions in d are reflected in dictproxy + del d[key] + assert len(dictproxy) == len(d) + assert key not in dictproxy + raises(KeyError, getitem, dictproxy, key) + raises(AttributeError, getattr, dictproxy, key) + + +class test_Plugin(ClassChecker): + """ + Tests the `plugable.Plugin` class. + """ + _cls = plugable.Plugin + + def test_class(self): + assert self.cls.__bases__ == (plugable.ReadOnly,) + assert self.cls.__public__ == frozenset() + assert type(self.cls.name) is property + assert type(self.cls.doc) is property + assert type(self.cls.api) is property + + def test_name(self): + """ + Tests the `plugable.Plugin.name` property. + """ + assert read_only(self.cls(), 'name') == 'Plugin' + + class some_subclass(self.cls): + pass + assert read_only(some_subclass(), 'name') == 'some_subclass' + + def test_doc(self): + """ + Tests the `plugable.Plugin.doc` property. + """ + class some_subclass(self.cls): + 'here is the doc string' + assert read_only(some_subclass(), 'doc') == 'here is the doc string' + + def test_implements(self): + """ + Tests the `plugable.Plugin.implements` classmethod. + """ + class example(self.cls): + __public__ = frozenset(( + 'some_method', + 'some_property', + )) + class superset(self.cls): + __public__ = frozenset(( + 'some_method', + 'some_property', + 'another_property', + )) + class subset(self.cls): + __public__ = frozenset(( + 'some_property', + )) + class any_object(object): + __public__ = frozenset(( + 'some_method', + 'some_property', + )) + + for ex in (example, example()): + # Test using str: + assert ex.implements('some_method') + assert not ex.implements('another_method') + + # Test using frozenset: + assert ex.implements(frozenset(['some_method'])) + assert not ex.implements( + frozenset(['some_method', 'another_method']) + ) + + # Test using another object/class with __public__ frozenset: + assert ex.implements(example) + assert ex.implements(example()) + + assert ex.implements(subset) + assert not subset.implements(ex) + + assert not ex.implements(superset) + assert superset.implements(ex) + + assert ex.implements(any_object) + assert ex.implements(any_object()) + + def test_implemented_by(self): + """ + Tests the `plugable.Plugin.implemented_by` classmethod. + """ + class base(self.cls): + __public__ = frozenset(( + 'attr0', + 'attr1', + 'attr2', + )) + + class okay(base): + def attr0(self): + pass + def __get_attr1(self): + assert False # Make sure property isn't accesed on instance + attr1 = property(__get_attr1) + attr2 = 'hello world' + another_attr = 'whatever' + + class fail(base): + def __init__(self): + # Check that class, not instance is inspected: + self.attr2 = 'hello world' + def attr0(self): + pass + def __get_attr1(self): + assert False # Make sure property isn't accesed on instance + attr1 = property(__get_attr1) + another_attr = 'whatever' + + # Test that AssertionError is raised trying to pass something not + # subclass nor instance of base: + raises(AssertionError, base.implemented_by, object) + + # Test on subclass with needed attributes: + assert base.implemented_by(okay) is True + assert base.implemented_by(okay()) is True + + # Test on subclass *without* needed attributes: + assert base.implemented_by(fail) is False + assert base.implemented_by(fail()) is False + + def test_set_api(self): + """ + Tests the `plugable.Plugin.set_api` method. + """ + api = 'the api instance' + o = self.cls() + assert o.api is None + e = raises(AssertionError, o.set_api, None) + assert str(e) == 'set_api() argument cannot be None' + o.set_api(api) + assert o.api is api + e = raises(AssertionError, o.set_api, api) + assert str(e) == 'set_api() can only be called once' + + def test_finalize(self): + """ + Tests the `plugable.Plugin.finalize` method. + """ + o = self.cls() + assert not o.__islocked__() + o.finalize() + assert o.__islocked__() + + +class test_PluginProxy(ClassChecker): + """ + Tests the `plugable.PluginProxy` class. + """ + _cls = plugable.PluginProxy + + def test_class(self): + assert self.cls.__bases__ == (plugable.SetProxy,) + + def test_proxy(self): + # Setup: + class base(object): + __public__ = frozenset(( + 'public_0', + 'public_1', + '__call__', + )) + + def public_0(self): + return 'public_0' + + def public_1(self): + return 'public_1' + + def __call__(self, caller): + return 'ya called it, %s.' % caller + + def private_0(self): + return 'private_0' + + def private_1(self): + return 'private_1' + + class plugin(base): + name = 'user_add' + attr_name = 'add' + doc = 'add a new user' + + # Test that TypeError is raised when base is not a class: + raises(TypeError, self.cls, base(), None) + + # Test that ValueError is raised when target is not instance of base: + raises(ValueError, self.cls, base, object()) + + # Test with correct arguments: + i = plugin() + p = self.cls(base, i) + assert read_only(p, 'name') is plugin.name + assert read_only(p, 'doc') == plugin.doc + assert list(p) == sorted(base.__public__) + + # Test normal methods: + for n in xrange(2): + pub = 'public_%d' % n + priv = 'private_%d' % n + assert getattr(i, pub)() == pub + assert getattr(p, pub)() == pub + assert hasattr(p, pub) + assert getattr(i, priv)() == priv + assert not hasattr(p, priv) + + # Test __call__: + value = 'ya called it, dude.' + assert i('dude') == value + assert p('dude') == value + assert callable(p) + + # Test name_attr='name' kw arg + i = plugin() + p = self.cls(base, i, 'attr_name') + assert read_only(p, 'name') == 'add' + + def test_implements(self): + """ + Tests the `plugable.PluginProxy.implements` method. + """ + class base(object): + __public__ = frozenset() + name = 'base' + doc = 'doc' + @classmethod + def implements(cls, arg): + return arg + 7 + + class sub(base): + @classmethod + def implements(cls, arg): + """ + Defined to make sure base.implements() is called, not + target.implements() + """ + return arg + + o = sub() + p = self.cls(base, o) + assert p.implements(3) == 10 + + def test_clone(self): + """ + Tests the `plugable.PluginProxy.__clone__` method. + """ + class base(object): + __public__ = frozenset() + class sub(base): + name = 'some_name' + doc = 'doc' + label = 'another_name' + + p = self.cls(base, sub()) + assert read_only(p, 'name') == 'some_name' + c = p.__clone__('label') + assert isinstance(c, self.cls) + assert c is not p + assert read_only(c, 'name') == 'another_name' + + +def test_check_name(): + """ + Tests the `plugable.check_name` function. + """ + f = plugable.check_name + okay = [ + 'user_add', + 'stuff2junk', + 'sixty9', + ] + nope = [ + '_user_add', + '__user_add', + 'user_add_', + 'user_add__', + '_user_add_', + '__user_add__', + '60nine', + ] + for name in okay: + assert name is f(name) + e = raises(TypeError, f, unicode(name)) + assert str(e) == errors.TYPE_FORMAT % ('name', str, unicode(name)) + for name in nope: + raises(errors.NameSpaceError, f, name) + for name in okay: + raises(errors.NameSpaceError, f, name.upper()) + +class DummyMember(object): + def __init__(self, i): + assert type(i) is int + self.name = 'member_%02d' % i + + +class test_NameSpace(ClassChecker): + """ + Tests the `plugable.NameSpace` class. + """ + _cls = plugable.NameSpace + + def test_class(self): + assert self.cls.__bases__ == (plugable.ReadOnly,) + + def test_init(self): + """ + Tests the `plugable.NameSpace.__init__` method. + """ + o = self.cls(tuple()) + assert list(o) == [] + assert list(o()) == [] + for cnt in (10, 25): + members = tuple(DummyMember(cnt - i) for i in xrange(cnt)) + for sort in (True, False): + o = self.cls(members, sort=sort) + if sort: + ordered = tuple(sorted(members, key=lambda m: m.name)) + else: + ordered = members + names = tuple(m.name for m in ordered) + assert o.__todict__() == dict((o.name, o) for o in ordered) + + # Test __len__: + assert len(o) == cnt + + # Test __contains__: + for name in names: + assert name in o + assert ('member_00') not in o + + # Test __iter__, __call__: + assert tuple(o) == names + assert tuple(o()) == ordered + + # Test __getitem__, getattr: + for (i, member) in enumerate(ordered): + assert o[i] is member + name = member.name + assert o[name] is member + assert read_only(o, name) is member + + # Test negative indexes: + for i in xrange(1, cnt + 1): + assert o[-i] is ordered[-i] + + # Test slices: + assert o[2:cnt-5] == ordered[2:cnt-5] + assert o[::3] == ordered[::3] + + # Test __repr__: + assert repr(o) == \ + 'NameSpace(<%d members>, sort=%r)' % (cnt, sort) + + +def test_Environment(): + """ + Tests the `plugable.Environment` class. + """ + # This has to be the same as iter_cnt + control_cnt = 0 + class prop_class: + def __init__(self, val): + self._val = val + def get_value(self): + return self._val + + class iter_class(prop_class): + # Increment this for each time iter_class yields + iter_cnt = 0 + def get_value(self): + for item in self._val: + self.__class__.iter_cnt += 1 + yield item + + # Tests for basic functionality + basic_tests = ( + ('a', 1), + ('b', 'basic_foo'), + ('c', ('basic_bar', 'basic_baz')), + ) + # Tests with prop classes + prop_tests = ( + ('d', prop_class(2), 2), + ('e', prop_class('prop_foo'), 'prop_foo'), + ('f', prop_class(('prop_bar', 'prop_baz')), ('prop_bar', 'prop_baz')), + ) + # Tests with iter classes + iter_tests = ( + ('g', iter_class((3, 4, 5)), (3, 4, 5)), + ('h', iter_class(('iter_foo', 'iter_bar', 'iter_baz')), + ('iter_foo', 'iter_bar', 'iter_baz') + ), + ) + + # Set all the values + env = plugable.Environment() + for name, val in basic_tests: + env[name] = val + for name, val, dummy in prop_tests: + env[name] = val + for name, val, dummy in iter_tests: + env[name] = val + + # Test if the values are correct + for name, val in basic_tests: + assert env[name] == val + for name, dummy, val in prop_tests: + assert env[name] == val + # Test if the get_value() function is called only when needed + for name, dummy, correct_values in iter_tests: + values_in_env = [] + for val in env[name]: + control_cnt += 1 + assert iter_class.iter_cnt == control_cnt + values_in_env.append(val) + assert tuple(values_in_env) == correct_values + + # Test __setattr__() + env.spam = 'ham' + assert env.spam == 'ham' + + # Test if we throw AttributeError exception when trying to overwrite + # existing value, or delete it + raises(AttributeError, setitem, env, 'a', 1) + raises(AttributeError, setattr, env, 'a', 1) + raises(AttributeError, delitem, env, 'a') + raises(AttributeError, delattr, env, 'a') + raises(AttributeError, plugable.Environment.update, env, dict(a=1000)) + # This should be silently ignored + env.update(dict(a=1000), True) + assert env.a != 1000 + +def test_Registrar(): + class Base1(object): + pass + class Base2(object): + pass + class Base3(object): + pass + class plugin1(Base1): + pass + class plugin2(Base2): + pass + class plugin3(Base3): + pass + + # Test creation of Registrar: + r = plugable.Registrar(Base1, Base2) + + # Test __iter__: + assert list(r) == ['Base1', 'Base2'] + + # Test __hasitem__, __getitem__: + for base in [Base1, Base2]: + name = base.__name__ + assert name in r + assert r[name] is base + magic = getattr(r, name) + assert type(magic) is plugable.MagicDict + assert len(magic) == 0 + + # Check that TypeError is raised trying to register something that isn't + # a class: + raises(TypeError, r, plugin1()) + + # Check that SubclassError is raised trying to register a class that is + # not a subclass of an allowed base: + raises(errors.SubclassError, r, plugin3) + + # Check that registration works + r(plugin1) + assert len(r.Base1) == 1 + assert r.Base1['plugin1'] is plugin1 + assert r.Base1.plugin1 is plugin1 + + # Check that DuplicateError is raised trying to register exact class + # again: + raises(errors.DuplicateError, r, plugin1) + + # Check that OverrideError is raised trying to register class with same + # name and same base: + orig1 = plugin1 + class base1_extended(Base1): + pass + class plugin1(base1_extended): + pass + raises(errors.OverrideError, r, plugin1) + + # Check that overriding works + r(plugin1, override=True) + assert len(r.Base1) == 1 + assert r.Base1.plugin1 is plugin1 + assert r.Base1.plugin1 is not orig1 + + # Check that MissingOverrideError is raised trying to override a name + # not yet registerd: + raises(errors.MissingOverrideError, r, plugin2, override=True) + + # Test that another plugin can be registered: + assert len(r.Base2) == 0 + r(plugin2) + assert len(r.Base2) == 1 + assert r.Base2.plugin2 is plugin2 + + # Setup to test more registration: + class plugin1a(Base1): + pass + r(plugin1a) + + class plugin1b(Base1): + pass + r(plugin1b) + + class plugin2a(Base2): + pass + r(plugin2a) + + class plugin2b(Base2): + pass + r(plugin2b) + + # Again test __hasitem__, __getitem__: + for base in [Base1, Base2]: + name = base.__name__ + assert name in r + assert r[name] is base + magic = getattr(r, name) + assert len(magic) == 3 + for key in magic: + klass = magic[key] + assert getattr(magic, key) is klass + assert issubclass(klass, base) + + + +def test_API(): + assert issubclass(plugable.API, plugable.ReadOnly) + + # Setup the test bases, create the API: + class base0(plugable.Plugin): + __public__ = frozenset(( + 'method', + )) + + def method(self, n): + return n + + class base1(plugable.Plugin): + __public__ = frozenset(( + 'method', + )) + + def method(self, n): + return n + 1 + + api = plugable.API(base0, base1) + r = api.register + assert isinstance(r, plugable.Registrar) + assert read_only(api, 'register') is r + + class base0_plugin0(base0): + pass + r(base0_plugin0) + + class base0_plugin1(base0): + pass + r(base0_plugin1) + + class base0_plugin2(base0): + pass + r(base0_plugin2) + + class base1_plugin0(base1): + pass + r(base1_plugin0) + + class base1_plugin1(base1): + pass + r(base1_plugin1) + + class base1_plugin2(base1): + pass + r(base1_plugin2) + + # Test API instance: + api.finalize() + + def get_base(b): + return 'base%d' % b + + def get_plugin(b, p): + return 'base%d_plugin%d' % (b, p) + + for b in xrange(2): + base_name = get_base(b) + ns = getattr(api, base_name) + assert isinstance(ns, plugable.NameSpace) + assert read_only(api, base_name) is ns + assert len(ns) == 3 + for p in xrange(3): + plugin_name = get_plugin(b, p) + proxy = ns[plugin_name] + assert isinstance(proxy, plugable.PluginProxy) + assert proxy.name == plugin_name + assert read_only(ns, plugin_name) is proxy + assert read_only(proxy, 'method')(7) == 7 + b + + # Test that calling finilize again raises AssertionError: + raises(AssertionError, api.finalize) + + # Test with base class that doesn't request a proxy + class NoProxy(plugable.Plugin): + __proxy__ = False + api = plugable.API(NoProxy) + class plugin0(NoProxy): + pass + api.register(plugin0) + class plugin1(NoProxy): + pass + api.register(plugin1) + api.finalize() + names = ['plugin0', 'plugin1'] + assert list(api.NoProxy) == names + for name in names: + plugin = api.NoProxy[name] + assert getattr(api.NoProxy, name) is plugin + assert isinstance(plugin, plugable.Plugin) + assert not isinstance(plugin, plugable.PluginProxy) diff --git a/tests/test_ipalib/test_tstutil.py b/tests/test_ipalib/test_tstutil.py new file mode 100644 index 00000000..5916f9d2 --- /dev/null +++ b/tests/test_ipalib/test_tstutil.py @@ -0,0 +1,148 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for test-helper `tests.tstutil` module. +""" + +import tstutil + + +class Prop(object): + def __init__(self, *ops): + self.__ops = frozenset(ops) + self.__prop = 'prop value' + + def __get_prop(self): + if 'get' not in self.__ops: + raise AttributeError('get prop') + return self.__prop + + def __set_prop(self, value): + if 'set' not in self.__ops: + raise AttributeError('set prop') + self.__prop = value + + def __del_prop(self): + if 'del' not in self.__ops: + raise AttributeError('del prop') + self.__prop = None + + prop = property(__get_prop, __set_prop, __del_prop) + + +def test_yes_raised(): + f = tstutil.raises + + class SomeError(Exception): + pass + + class AnotherError(Exception): + pass + + def callback1(): + 'raises correct exception' + raise SomeError() + + def callback2(): + 'raises wrong exception' + raise AnotherError() + + def callback3(): + 'raises no exception' + + f(SomeError, callback1) + + raised = False + try: + f(SomeError, callback2) + except AnotherError: + raised = True + assert raised + + raised = False + try: + f(SomeError, callback3) + except tstutil.ExceptionNotRaised: + raised = True + assert raised + + +def test_no_set(): + # Tests that it works when prop cannot be set: + tstutil.no_set(Prop('get', 'del'), 'prop') + + # Tests that ExceptionNotRaised is raised when prop *can* be set: + raised = False + try: + tstutil.no_set(Prop('set'), 'prop') + except tstutil.ExceptionNotRaised: + raised = True + assert raised + + +def test_no_del(): + # Tests that it works when prop cannot be deleted: + tstutil.no_del(Prop('get', 'set'), 'prop') + + # Tests that ExceptionNotRaised is raised when prop *can* be set: + raised = False + try: + tstutil.no_del(Prop('del'), 'prop') + except tstutil.ExceptionNotRaised: + raised = True + assert raised + + +def test_read_only(): + # Test that it works when prop is read only: + assert tstutil.read_only(Prop('get'), 'prop') == 'prop value' + + # Test that ExceptionNotRaised is raised when prop can be set: + raised = False + try: + tstutil.read_only(Prop('get', 'set'), 'prop') + except tstutil.ExceptionNotRaised: + raised = True + assert raised + + # Test that ExceptionNotRaised is raised when prop can be deleted: + raised = False + try: + tstutil.read_only(Prop('get', 'del'), 'prop') + except tstutil.ExceptionNotRaised: + raised = True + assert raised + + # Test that ExceptionNotRaised is raised when prop can be both set and + # deleted: + raised = False + try: + tstutil.read_only(Prop('get', 'del'), 'prop') + except tstutil.ExceptionNotRaised: + raised = True + assert raised + + # Test that AttributeError is raised when prop can't be read: + raised = False + try: + tstutil.read_only(Prop(), 'prop') + except AttributeError: + raised = True + assert raised diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py new file mode 100644 index 00000000..f8ee0bf4 --- /dev/null +++ b/tests/test_ipalib/test_util.py @@ -0,0 +1,49 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Unit tests for `ipalib.util` module. +""" + +from tstutil import raises +from ipalib import util + + +def test_xmlrpc_marshal(): + """ + Test the `util.xmlrpc_marshal` function. + """ + f = util.xmlrpc_marshal + assert f() == ({},) + assert f('one', 'two') == ({}, 'one', 'two') + assert f(one=1, two=2) == (dict(one=1, two=2),) + assert f('one', 'two', three=3, four=4) == \ + (dict(three=3, four=4), 'one', 'two') + + +def test_xmlrpc_unmarshal(): + """ + Test the `util.xmlrpc_unmarshal` function. + """ + f = util.xmlrpc_unmarshal + assert f() == (tuple(), {}) + assert f({}, 'one', 'two') == (('one', 'two'), {}) + assert f(dict(one=1, two=2)) == (tuple(), dict(one=1, two=2)) + assert f(dict(three=3, four=4), 'one', 'two') == \ + (('one', 'two'), dict(three=3, four=4)) diff --git a/tests/test_ipalib/tstutil.py b/tests/test_ipalib/tstutil.py new file mode 100644 index 00000000..743716a0 --- /dev/null +++ b/tests/test_ipalib/tstutil.py @@ -0,0 +1,147 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 + +""" +Utility functions for the unit tests. +""" + +import inspect +from ipalib import errors + +class ExceptionNotRaised(Exception): + """ + Exception raised when an *expected* exception is *not* raised during a + unit test. + """ + msg = 'expected %s' + + def __init__(self, expected): + self.expected = expected + + def __str__(self): + return self.msg % self.expected.__name__ + + +def raises(exception, callback, *args, **kw): + """ + Tests that the expected exception is raised; raises ExceptionNotRaised + if test fails. + """ + raised = False + try: + callback(*args, **kw) + except exception, e: + raised = True + if not raised: + raise ExceptionNotRaised(exception) + return e + + +def getitem(obj, key): + """ + Works like getattr but for dictionary interface. Use this in combination + with raises() to test that, for example, KeyError is raised. + """ + return obj[key] + + +def setitem(obj, key, value): + """ + Works like setattr but for dictionary interface. Use this in combination + with raises() to test that, for example, TypeError is raised. + """ + obj[key] = value + + +def delitem(obj, key): + """ + Works like delattr but for dictionary interface. Use this in combination + with raises() to test that, for example, TypeError is raised. + """ + del obj[key] + + +def no_set(obj, name, value='some_new_obj'): + """ + Tests that attribute cannot be set. + """ + raises(AttributeError, setattr, obj, name, value) + + +def no_del(obj, name): + """ + Tests that attribute cannot be deleted. + """ + raises(AttributeError, delattr, obj, name) + + +def read_only(obj, name, value='some_new_obj'): + """ + Tests that attribute is read-only. Returns attribute. + """ + # Test that it cannot be set: + no_set(obj, name, value) + + # Test that it cannot be deleted: + no_del(obj, name) + + # Return the attribute + return getattr(obj, name) + + +def is_prop(prop): + return type(prop) is property + + +class ClassChecker(object): + __cls = None + __subcls = None + + def __get_cls(self): + if self.__cls is None: + self.__cls = self._cls + assert inspect.isclass(self.__cls) + return self.__cls + cls = property(__get_cls) + + def __get_subcls(self): + if self.__subcls is None: + self.__subcls = self.get_subcls() + assert inspect.isclass(self.__subcls) + return self.__subcls + subcls = property(__get_subcls) + + def get_subcls(self): + raise NotImplementedError( + self.__class__.__name__, + 'get_subcls()' + ) + + +def check_TypeError(value, type_, name, callback, *args, **kw): + """ + Tests a standard TypeError raised with `errors.raise_TypeError`. + """ + e = raises(TypeError, callback, *args, **kw) + assert e.value is value + assert e.type is type_ + assert e.name == name + assert type(e.name) is str + assert str(e) == errors.TYPE_FORMAT % (name, type_, value) + return e -- cgit From af56c71d506c2573f99a1ca8334cfa90dc7f74d7 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 21:25:23 -0600 Subject: Cleaned up package and module level docstrings for everything in tests/ --- tests/test_ipalib/__init__.py | 2 +- tests/test_ipalib/test_backend.py | 2 +- tests/test_ipalib/test_cli.py | 2 +- tests/test_ipalib/test_config.py | 2 +- tests/test_ipalib/test_crud.py | 2 +- tests/test_ipalib/test_errors.py | 2 +- tests/test_ipalib/test_frontend.py | 2 +- tests/test_ipalib/test_ipa_types.py | 2 +- tests/test_ipalib/test_plugable.py | 2 +- tests/test_ipalib/test_tstutil.py | 2 +- tests/test_ipalib/test_util.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/__init__.py b/tests/test_ipalib/__init__.py index d3658c45..b12bccc5 100644 --- a/tests/test_ipalib/__init__.py +++ b/tests/test_ipalib/__init__.py @@ -18,5 +18,5 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib` package. +Test the `ipalib` package. """ diff --git a/tests/test_ipalib/test_backend.py b/tests/test_ipalib/test_backend.py index 967e9fdf..ddf66540 100644 --- a/tests/test_ipalib/test_backend.py +++ b/tests/test_ipalib/test_backend.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.backend` module. +Test the `ipalib.backend` module. """ from ipalib import backend, plugable, errors diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 90c66d41..4095af6d 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.cli` module. +Test the `ipalib.cli` module. """ from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index de7d4c22..242ce16b 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.config` module. +Test the `ipalib.config` module. """ import types diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index 9355f237..fbfbfab1 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.crud` module. +Test the `ipalib.crud` module. """ from tstutil import read_only, raises, ClassChecker diff --git a/tests/test_ipalib/test_errors.py b/tests/test_ipalib/test_errors.py index 7d2df4df..7c81cf62 100644 --- a/tests/test_ipalib/test_errors.py +++ b/tests/test_ipalib/test_errors.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.errors` module. +Test the `ipalib.errors` module. """ from tstutil import raises, ClassChecker diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index c70cc00d..d99c7bd9 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.frontend` module. +Test the `ipalib.frontend` module. """ from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker diff --git a/tests/test_ipalib/test_ipa_types.py b/tests/test_ipalib/test_ipa_types.py index b8e996a7..81261a35 100644 --- a/tests/test_ipalib/test_ipa_types.py +++ b/tests/test_ipalib/test_ipa_types.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.ipa_types` module. +Test the `ipalib.ipa_types` module. """ from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index fd3c3c88..759ec3c4 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.plugable` module. +Test the `ipalib.plugable` module. """ from tstutil import raises, no_set, no_del, read_only diff --git a/tests/test_ipalib/test_tstutil.py b/tests/test_ipalib/test_tstutil.py index 5916f9d2..c441ddb8 100644 --- a/tests/test_ipalib/test_tstutil.py +++ b/tests/test_ipalib/test_tstutil.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for test-helper `tests.tstutil` module. +Test the `tests.tstutil` module. """ import tstutil diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index f8ee0bf4..0423ad62 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Unit tests for `ipalib.util` module. +Test the `ipalib.util` module. """ from tstutil import raises -- cgit From f6ac2df6bd7ceddd0f3eb968198cc3ebd1388087 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 21:59:47 -0600 Subject: Moved tstutil.py into base of tests so it can be used by all test subpackages more easily --- tests/test_ipalib/test_backend.py | 2 +- tests/test_ipalib/test_cli.py | 2 +- tests/test_ipalib/test_config.py | 2 +- tests/test_ipalib/test_crud.py | 2 +- tests/test_ipalib/test_errors.py | 2 +- tests/test_ipalib/test_frontend.py | 4 +- tests/test_ipalib/test_ipa_types.py | 2 +- tests/test_ipalib/test_plugable.py | 6 +- tests/test_ipalib/test_tstutil.py | 148 ------------------------------------ tests/test_ipalib/test_util.py | 2 +- tests/test_ipalib/tstutil.py | 147 ----------------------------------- 11 files changed, 12 insertions(+), 307 deletions(-) delete mode 100644 tests/test_ipalib/test_tstutil.py delete mode 100644 tests/test_ipalib/tstutil.py (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_backend.py b/tests/test_ipalib/test_backend.py index ddf66540..07c5eb00 100644 --- a/tests/test_ipalib/test_backend.py +++ b/tests/test_ipalib/test_backend.py @@ -22,7 +22,7 @@ Test the `ipalib.backend` module. """ from ipalib import backend, plugable, errors -from tstutil import ClassChecker +from tests.tstutil import ClassChecker class test_Backend(ClassChecker): diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 4095af6d..c7b37126 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -21,7 +21,7 @@ Test the `ipalib.cli` module. """ -from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker +from tests.tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker from ipalib import cli, plugable diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 242ce16b..a1329fa4 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -23,7 +23,7 @@ Test the `ipalib.config` module. import types -from tstutil import raises +from tests.tstutil import raises from ipalib import config diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index fbfbfab1..e2dd60aa 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -21,7 +21,7 @@ Test the `ipalib.crud` module. """ -from tstutil import read_only, raises, ClassChecker +from tests.tstutil import read_only, raises, ClassChecker from ipalib import crud, frontend, plugable, config def get_api(): diff --git a/tests/test_ipalib/test_errors.py b/tests/test_ipalib/test_errors.py index 7c81cf62..bb729776 100644 --- a/tests/test_ipalib/test_errors.py +++ b/tests/test_ipalib/test_errors.py @@ -21,7 +21,7 @@ Test the `ipalib.errors` module. """ -from tstutil import raises, ClassChecker +from tests.tstutil import raises, ClassChecker from ipalib import errors diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index d99c7bd9..320e2078 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -21,8 +21,8 @@ Test the `ipalib.frontend` module. """ -from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker -from tstutil import check_TypeError +from tests.tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker +from tests.tstutil import check_TypeError from ipalib import frontend, backend, plugable, errors, ipa_types, config diff --git a/tests/test_ipalib/test_ipa_types.py b/tests/test_ipalib/test_ipa_types.py index 81261a35..0b8b728e 100644 --- a/tests/test_ipalib/test_ipa_types.py +++ b/tests/test_ipalib/test_ipa_types.py @@ -21,7 +21,7 @@ Test the `ipalib.ipa_types` module. """ -from tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker +from tests.tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker from ipalib import ipa_types, errors, plugable diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 759ec3c4..bfd7259f 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -21,9 +21,9 @@ Test the `ipalib.plugable` module. """ -from tstutil import raises, no_set, no_del, read_only -from tstutil import getitem, setitem, delitem -from tstutil import ClassChecker +from tests.tstutil import raises, no_set, no_del, read_only +from tests.tstutil import getitem, setitem, delitem +from tests.tstutil import ClassChecker from ipalib import plugable, errors diff --git a/tests/test_ipalib/test_tstutil.py b/tests/test_ipalib/test_tstutil.py deleted file mode 100644 index c441ddb8..00000000 --- a/tests/test_ipalib/test_tstutil.py +++ /dev/null @@ -1,148 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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 `tests.tstutil` module. -""" - -import tstutil - - -class Prop(object): - def __init__(self, *ops): - self.__ops = frozenset(ops) - self.__prop = 'prop value' - - def __get_prop(self): - if 'get' not in self.__ops: - raise AttributeError('get prop') - return self.__prop - - def __set_prop(self, value): - if 'set' not in self.__ops: - raise AttributeError('set prop') - self.__prop = value - - def __del_prop(self): - if 'del' not in self.__ops: - raise AttributeError('del prop') - self.__prop = None - - prop = property(__get_prop, __set_prop, __del_prop) - - -def test_yes_raised(): - f = tstutil.raises - - class SomeError(Exception): - pass - - class AnotherError(Exception): - pass - - def callback1(): - 'raises correct exception' - raise SomeError() - - def callback2(): - 'raises wrong exception' - raise AnotherError() - - def callback3(): - 'raises no exception' - - f(SomeError, callback1) - - raised = False - try: - f(SomeError, callback2) - except AnotherError: - raised = True - assert raised - - raised = False - try: - f(SomeError, callback3) - except tstutil.ExceptionNotRaised: - raised = True - assert raised - - -def test_no_set(): - # Tests that it works when prop cannot be set: - tstutil.no_set(Prop('get', 'del'), 'prop') - - # Tests that ExceptionNotRaised is raised when prop *can* be set: - raised = False - try: - tstutil.no_set(Prop('set'), 'prop') - except tstutil.ExceptionNotRaised: - raised = True - assert raised - - -def test_no_del(): - # Tests that it works when prop cannot be deleted: - tstutil.no_del(Prop('get', 'set'), 'prop') - - # Tests that ExceptionNotRaised is raised when prop *can* be set: - raised = False - try: - tstutil.no_del(Prop('del'), 'prop') - except tstutil.ExceptionNotRaised: - raised = True - assert raised - - -def test_read_only(): - # Test that it works when prop is read only: - assert tstutil.read_only(Prop('get'), 'prop') == 'prop value' - - # Test that ExceptionNotRaised is raised when prop can be set: - raised = False - try: - tstutil.read_only(Prop('get', 'set'), 'prop') - except tstutil.ExceptionNotRaised: - raised = True - assert raised - - # Test that ExceptionNotRaised is raised when prop can be deleted: - raised = False - try: - tstutil.read_only(Prop('get', 'del'), 'prop') - except tstutil.ExceptionNotRaised: - raised = True - assert raised - - # Test that ExceptionNotRaised is raised when prop can be both set and - # deleted: - raised = False - try: - tstutil.read_only(Prop('get', 'del'), 'prop') - except tstutil.ExceptionNotRaised: - raised = True - assert raised - - # Test that AttributeError is raised when prop can't be read: - raised = False - try: - tstutil.read_only(Prop(), 'prop') - except AttributeError: - raised = True - assert raised diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index 0423ad62..5b8b13f7 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -21,7 +21,7 @@ Test the `ipalib.util` module. """ -from tstutil import raises +from tests.tstutil import raises from ipalib import util diff --git a/tests/test_ipalib/tstutil.py b/tests/test_ipalib/tstutil.py deleted file mode 100644 index 743716a0..00000000 --- a/tests/test_ipalib/tstutil.py +++ /dev/null @@ -1,147 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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 - -""" -Utility functions for the unit tests. -""" - -import inspect -from ipalib import errors - -class ExceptionNotRaised(Exception): - """ - Exception raised when an *expected* exception is *not* raised during a - unit test. - """ - msg = 'expected %s' - - def __init__(self, expected): - self.expected = expected - - def __str__(self): - return self.msg % self.expected.__name__ - - -def raises(exception, callback, *args, **kw): - """ - Tests that the expected exception is raised; raises ExceptionNotRaised - if test fails. - """ - raised = False - try: - callback(*args, **kw) - except exception, e: - raised = True - if not raised: - raise ExceptionNotRaised(exception) - return e - - -def getitem(obj, key): - """ - Works like getattr but for dictionary interface. Use this in combination - with raises() to test that, for example, KeyError is raised. - """ - return obj[key] - - -def setitem(obj, key, value): - """ - Works like setattr but for dictionary interface. Use this in combination - with raises() to test that, for example, TypeError is raised. - """ - obj[key] = value - - -def delitem(obj, key): - """ - Works like delattr but for dictionary interface. Use this in combination - with raises() to test that, for example, TypeError is raised. - """ - del obj[key] - - -def no_set(obj, name, value='some_new_obj'): - """ - Tests that attribute cannot be set. - """ - raises(AttributeError, setattr, obj, name, value) - - -def no_del(obj, name): - """ - Tests that attribute cannot be deleted. - """ - raises(AttributeError, delattr, obj, name) - - -def read_only(obj, name, value='some_new_obj'): - """ - Tests that attribute is read-only. Returns attribute. - """ - # Test that it cannot be set: - no_set(obj, name, value) - - # Test that it cannot be deleted: - no_del(obj, name) - - # Return the attribute - return getattr(obj, name) - - -def is_prop(prop): - return type(prop) is property - - -class ClassChecker(object): - __cls = None - __subcls = None - - def __get_cls(self): - if self.__cls is None: - self.__cls = self._cls - assert inspect.isclass(self.__cls) - return self.__cls - cls = property(__get_cls) - - def __get_subcls(self): - if self.__subcls is None: - self.__subcls = self.get_subcls() - assert inspect.isclass(self.__subcls) - return self.__subcls - subcls = property(__get_subcls) - - def get_subcls(self): - raise NotImplementedError( - self.__class__.__name__, - 'get_subcls()' - ) - - -def check_TypeError(value, type_, name, callback, *args, **kw): - """ - Tests a standard TypeError raised with `errors.raise_TypeError`. - """ - e = raises(TypeError, callback, *args, **kw) - assert e.value is value - assert e.type is type_ - assert e.name == name - assert type(e.name) is str - assert str(e) == errors.TYPE_FORMAT % (name, type_, value) - return e -- cgit From deb8e3dfc899cfc7ee31f47c1ba7c4301c58fc51 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 22:30:53 -0600 Subject: Renamed tests/tstutil.py to tests/util.py --- tests/test_ipalib/test_backend.py | 2 +- tests/test_ipalib/test_cli.py | 2 +- tests/test_ipalib/test_config.py | 2 +- tests/test_ipalib/test_crud.py | 2 +- tests/test_ipalib/test_errors.py | 2 +- tests/test_ipalib/test_frontend.py | 4 ++-- tests/test_ipalib/test_ipa_types.py | 2 +- tests/test_ipalib/test_plugable.py | 6 +++--- tests/test_ipalib/test_util.py | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_backend.py b/tests/test_ipalib/test_backend.py index 07c5eb00..cd490fe0 100644 --- a/tests/test_ipalib/test_backend.py +++ b/tests/test_ipalib/test_backend.py @@ -22,7 +22,7 @@ Test the `ipalib.backend` module. """ from ipalib import backend, plugable, errors -from tests.tstutil import ClassChecker +from tests.util import ClassChecker class test_Backend(ClassChecker): diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index c7b37126..33e4d220 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -21,7 +21,7 @@ Test the `ipalib.cli` module. """ -from tests.tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker +from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker from ipalib import cli, plugable diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index a1329fa4..7b12a53e 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -23,7 +23,7 @@ Test the `ipalib.config` module. import types -from tests.tstutil import raises +from tests.util import raises from ipalib import config diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index e2dd60aa..3113ec69 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -21,7 +21,7 @@ Test the `ipalib.crud` module. """ -from tests.tstutil import read_only, raises, ClassChecker +from tests.util import read_only, raises, ClassChecker from ipalib import crud, frontend, plugable, config def get_api(): diff --git a/tests/test_ipalib/test_errors.py b/tests/test_ipalib/test_errors.py index bb729776..8db810da 100644 --- a/tests/test_ipalib/test_errors.py +++ b/tests/test_ipalib/test_errors.py @@ -21,7 +21,7 @@ Test the `ipalib.errors` module. """ -from tests.tstutil import raises, ClassChecker +from tests.util import raises, ClassChecker from ipalib import errors diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 320e2078..4b1b56cf 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -21,8 +21,8 @@ Test the `ipalib.frontend` module. """ -from tests.tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker -from tests.tstutil import check_TypeError +from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker +from tests.util import check_TypeError from ipalib import frontend, backend, plugable, errors, ipa_types, config diff --git a/tests/test_ipalib/test_ipa_types.py b/tests/test_ipalib/test_ipa_types.py index 0b8b728e..65d1f63d 100644 --- a/tests/test_ipalib/test_ipa_types.py +++ b/tests/test_ipalib/test_ipa_types.py @@ -21,7 +21,7 @@ Test the `ipalib.ipa_types` module. """ -from tests.tstutil import raises, getitem, no_set, no_del, read_only, ClassChecker +from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker from ipalib import ipa_types, errors, plugable diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index bfd7259f..783a450a 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -21,9 +21,9 @@ Test the `ipalib.plugable` module. """ -from tests.tstutil import raises, no_set, no_del, read_only -from tests.tstutil import getitem, setitem, delitem -from tests.tstutil import ClassChecker +from tests.util import raises, no_set, no_del, read_only +from tests.util import getitem, setitem, delitem +from tests.util import ClassChecker from ipalib import plugable, errors diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index 5b8b13f7..04ff23f0 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -21,7 +21,7 @@ Test the `ipalib.util` module. """ -from tests.tstutil import raises +from tests.util import raises from ipalib import util -- cgit From 97634e18c78677c5568e2783191f4a6bc4512105 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 23:20:00 -0600 Subject: PEP 257: cleaned up docstrings in test_plugable.py --- tests/test_ipalib/test_plugable.py | 93 ++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 24 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 783a450a..3cdf1808 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -29,18 +29,21 @@ from ipalib import plugable, errors class test_ReadOnly(ClassChecker): """ - Test the `plugable.ReadOnly` class + Test the `ipalib.plugable.ReadOnly` class """ _cls = plugable.ReadOnly def test_class(self): + """ + Test the `ipalib.plugable.ReadOnly` class + """ assert self.cls.__bases__ == (object,) assert callable(self.cls.__lock__) assert callable(self.cls.__islocked__) def test_lock(self): """ - Test the `plugable.ReadOnly.__lock__` method. + Test the `ipalib.plugable.ReadOnly.__lock__` method. """ o = self.cls() assert o._ReadOnly__locked is False @@ -52,7 +55,7 @@ class test_ReadOnly(ClassChecker): def test_lock(self): """ - Test the `plugable.ReadOnly.__islocked__` method. + Test the `ipalib.plugable.ReadOnly.__islocked__` method. """ o = self.cls() assert o.__islocked__() is False @@ -61,7 +64,7 @@ class test_ReadOnly(ClassChecker): def test_setattr(self): """ - Test the `plugable.ReadOnly.__setattr__` method. + Test the `ipalib.plugable.ReadOnly.__setattr__` method. """ o = self.cls() o.attr1 = 'Hello, world!' @@ -74,7 +77,7 @@ class test_ReadOnly(ClassChecker): def test_delattr(self): """ - Test the `plugable.ReadOnly.__delattr__` method. + Test the `ipalib.plugable.ReadOnly.__delattr__` method. """ o = self.cls() o.attr1 = 'Hello, world!' @@ -91,7 +94,7 @@ class test_ReadOnly(ClassChecker): def test_lock(): """ - Tests the `plugable.lock` function. + Test the `ipalib.plugable.lock` function. """ f = plugable.lock @@ -120,14 +123,20 @@ def test_lock(): class test_SetProxy(ClassChecker): """ - Tests the `plugable.SetProxy` class. + Test the `ipalib.plugable.SetProxy` class. """ _cls = plugable.SetProxy def test_class(self): + """ + Test the `ipalib.plugable.SetProxy` class. + """ assert self.cls.__bases__ == (plugable.ReadOnly,) def test_init(self): + """ + Test the `ipalib.plugable.SetProxy.__init__` method. + """ okay = (set, frozenset, dict) fail = (list, tuple) for t in okay: @@ -138,6 +147,9 @@ class test_SetProxy(ClassChecker): raises(TypeError, self.cls, t) def test_SetProxy(self): + """ + Test container emulation of `ipalib.plugable.SetProxy` class. + """ def get_key(i): return 'key_%d' % i @@ -163,14 +175,20 @@ class test_SetProxy(ClassChecker): class test_DictProxy(ClassChecker): """ - Tests the `plugable.DictProxy` class. + Test the `ipalib.plugable.DictProxy` class. """ _cls = plugable.DictProxy def test_class(self): + """ + Test the `ipalib.plugable.DictProxy` class. + """ assert self.cls.__bases__ == (plugable.SetProxy,) def test_init(self): + """ + Test the `ipalib.plugable.DictProxy.__init__` method. + """ self.cls(dict()) raises(TypeError, self.cls, dict) fail = (set, frozenset, list, tuple) @@ -179,6 +197,9 @@ class test_DictProxy(ClassChecker): raises(TypeError, self.cls, t) def test_DictProxy(self): + """ + Test container emulation of `ipalib.plugable.DictProxy` class. + """ def get_kv(i): return ( 'key_%d' % i, @@ -210,16 +231,22 @@ class test_DictProxy(ClassChecker): class test_MagicDict(ClassChecker): """ - Tests the `plugable.MagicDict` class. + Tests the `ipalib.plugable.MagicDict` class. """ _cls = plugable.MagicDict def test_class(self): + """ + Tests the `ipalib.plugable.MagicDict` class. + """ assert self.cls.__bases__ == (plugable.DictProxy,) for non_dict in ('hello', 69, object): raises(TypeError, self.cls, non_dict) def test_MagicDict(self): + """ + Test container emulation of `ipalib.plugable.MagicDict` class. + """ cnt = 10 keys = [] d = dict() @@ -266,11 +293,14 @@ class test_MagicDict(ClassChecker): class test_Plugin(ClassChecker): """ - Tests the `plugable.Plugin` class. + Test the `ipalib.plugable.Plugin` class. """ _cls = plugable.Plugin def test_class(self): + """ + Test the `ipalib.plugable.Plugin` class. + """ assert self.cls.__bases__ == (plugable.ReadOnly,) assert self.cls.__public__ == frozenset() assert type(self.cls.name) is property @@ -279,7 +309,7 @@ class test_Plugin(ClassChecker): def test_name(self): """ - Tests the `plugable.Plugin.name` property. + Test the `ipalib.plugable.Plugin.name` property. """ assert read_only(self.cls(), 'name') == 'Plugin' @@ -289,7 +319,7 @@ class test_Plugin(ClassChecker): def test_doc(self): """ - Tests the `plugable.Plugin.doc` property. + Test the `ipalib.plugable.Plugin.doc` property. """ class some_subclass(self.cls): 'here is the doc string' @@ -297,7 +327,7 @@ class test_Plugin(ClassChecker): def test_implements(self): """ - Tests the `plugable.Plugin.implements` classmethod. + Test the `ipalib.plugable.Plugin.implements` classmethod. """ class example(self.cls): __public__ = frozenset(( @@ -346,7 +376,7 @@ class test_Plugin(ClassChecker): def test_implemented_by(self): """ - Tests the `plugable.Plugin.implemented_by` classmethod. + Test the `ipalib.plugable.Plugin.implemented_by` classmethod. """ class base(self.cls): __public__ = frozenset(( @@ -389,7 +419,7 @@ class test_Plugin(ClassChecker): def test_set_api(self): """ - Tests the `plugable.Plugin.set_api` method. + Test the `ipalib.plugable.Plugin.set_api` method. """ api = 'the api instance' o = self.cls() @@ -403,7 +433,7 @@ class test_Plugin(ClassChecker): def test_finalize(self): """ - Tests the `plugable.Plugin.finalize` method. + Test the `ipalib.plugable.Plugin.finalize` method. """ o = self.cls() assert not o.__islocked__() @@ -413,14 +443,20 @@ class test_Plugin(ClassChecker): class test_PluginProxy(ClassChecker): """ - Tests the `plugable.PluginProxy` class. + Test the `ipalib.plugable.PluginProxy` class. """ _cls = plugable.PluginProxy def test_class(self): + """ + Test the `ipalib.plugable.PluginProxy` class. + """ assert self.cls.__bases__ == (plugable.SetProxy,) def test_proxy(self): + """ + Test proxy behaviour of `ipalib.plugable.PluginProxy` instance. + """ # Setup: class base(object): __public__ = frozenset(( @@ -485,7 +521,7 @@ class test_PluginProxy(ClassChecker): def test_implements(self): """ - Tests the `plugable.PluginProxy.implements` method. + Test the `ipalib.plugable.PluginProxy.implements` method. """ class base(object): __public__ = frozenset() @@ -510,7 +546,7 @@ class test_PluginProxy(ClassChecker): def test_clone(self): """ - Tests the `plugable.PluginProxy.__clone__` method. + Test the `ipalib.plugable.PluginProxy.__clone__` method. """ class base(object): __public__ = frozenset() @@ -529,7 +565,7 @@ class test_PluginProxy(ClassChecker): def test_check_name(): """ - Tests the `plugable.check_name` function. + Test the `ipalib.plugable.check_name` function. """ f = plugable.check_name okay = [ @@ -563,16 +599,19 @@ class DummyMember(object): class test_NameSpace(ClassChecker): """ - Tests the `plugable.NameSpace` class. + Test the `ipalib.plugable.NameSpace` class. """ _cls = plugable.NameSpace def test_class(self): + """ + Test the `ipalib.plugable.NameSpace` class. + """ assert self.cls.__bases__ == (plugable.ReadOnly,) def test_init(self): """ - Tests the `plugable.NameSpace.__init__` method. + Test the `ipalib.plugable.NameSpace.__init__` method. """ o = self.cls(tuple()) assert list(o) == [] @@ -622,7 +661,7 @@ class test_NameSpace(ClassChecker): def test_Environment(): """ - Tests the `plugable.Environment` class. + Test the `ipalib.plugable.Environment` class. """ # This has to be the same as iter_cnt control_cnt = 0 @@ -698,7 +737,11 @@ def test_Environment(): env.update(dict(a=1000), True) assert env.a != 1000 + def test_Registrar(): + """ + Test the `ipalib.plugable.Registrar` class + """ class Base1(object): pass class Base2(object): @@ -800,8 +843,10 @@ def test_Registrar(): assert issubclass(klass, base) - def test_API(): + """ + Test the `ipalib.plugable.API` class. + """ assert issubclass(plugable.API, plugable.ReadOnly) # Setup the test bases, create the API: -- cgit From 9bff91fc0871cc9aa02e1fd63776a303185f3b3c Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 23:29:42 -0600 Subject: PEP 257: cleaned up docstrings in test_cli.py --- tests/test_ipalib/test_cli.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 33e4d220..50bfb932 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -27,7 +27,7 @@ from ipalib import cli, plugable def test_to_cli(): """ - Tests the `cli.to_cli` function. + Test the `ipalib.cli.to_cli` function. """ f = cli.to_cli assert f('initialize') == 'initialize' @@ -36,7 +36,7 @@ def test_to_cli(): def test_from_cli(): """ - Tests the `cli.from_cli` function. + Test the `ipalib.cli.from_cli` function. """ f = cli.from_cli assert f('initialize') == 'initialize' @@ -46,6 +46,7 @@ def test_from_cli(): def get_cmd_name(i): return 'cmd_%d' % i + class DummyCommand(object): def __init__(self, name): self.__name = name @@ -54,6 +55,7 @@ class DummyCommand(object): return self.__name name = property(__get_name) + class DummyAPI(object): def __init__(self, cnt): self.__cmd = plugable.NameSpace(self.__cmd_iter(cnt)) @@ -73,21 +75,21 @@ class DummyAPI(object): pass - - - class test_CLI(ClassChecker): """ - Tests the `cli.CLI` class. + Test the `ipalib.cli.CLI` class. """ _cls = cli.CLI def test_class(self): + """ + Test the `ipalib.cli.CLI` class. + """ assert type(self.cls.api) is property def test_api(self): """ - Tests the `cli.CLI.api` property. + Test the `ipalib.cli.CLI.api` property. """ api = 'the plugable.API instance' o = self.cls(api) @@ -95,7 +97,7 @@ class test_CLI(ClassChecker): def dont_parse(self): """ - Tests the `cli.CLI.parse` method. + Test the `ipalib.cli.CLI.parse` method. """ o = self.cls(None) args = ['hello', 'naughty', 'nurse'] @@ -111,7 +113,7 @@ class test_CLI(ClassChecker): def test_mcl(self): """ - Tests the `cli.CLI.mcl` (Max Command Length) property . + Test the `ipalib.cli.CLI.mcl` property . """ cnt = 100 api = DummyAPI(cnt) @@ -123,7 +125,7 @@ class test_CLI(ClassChecker): def test_dict(self): """ - Tests the `cli.CLI.__contains__` and `cli.CLI.__getitem__` methods. + Test container emulation of `ipalib.cli.CLI` class. """ cnt = 25 api = DummyAPI(cnt) -- cgit From 0d2b5a889237165a9870668d9f97787606524e32 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 23:31:40 -0600 Subject: PEP 257: cleaned up docstrings in test_config.py --- tests/test_ipalib/test_config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 7b12a53e..2ec75048 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -29,7 +29,7 @@ from ipalib import config def test_generate_env(): """ - Test the `config.generate_env` function + Test the `ipalib.config.generate_env` function. """ # Make sure we don't overwrite any properties @@ -49,7 +49,7 @@ def test_generate_env(): def test_LazyProp(): """ - Test the `config.LazyProp` class + Test the `ipalib.config.LazyProp` class. """ def dummy(): @@ -70,7 +70,7 @@ def test_LazyProp(): def test_LazyIter(): """ - Test the `config.LazyIter` class + Test the `ipalib.config.LazyIter` class. """ def dummy(): @@ -95,7 +95,7 @@ def test_LazyIter(): def test_read_config(): """ - Test the `config.read_config` class + Test the `ipalib.config.read_config` class. """ raises(AssertionError, config.read_config, 1) -- cgit From f5ea3b1bb9430978cee6799d68f71da79bb4fd3a Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 23:36:58 -0600 Subject: Made docstrings in test_crud.py contistent with rest --- tests/test_ipalib/test_crud.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index 3113ec69..eb8be643 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -24,6 +24,7 @@ Test the `ipalib.crud` module. from tests.util import read_only, raises, ClassChecker from ipalib import crud, frontend, plugable, config + def get_api(): api = plugable.API( frontend.Object, @@ -44,17 +45,20 @@ def get_api(): class test_Add(ClassChecker): """ - Test the `crud.Add` class. + Test the `ipalib.crud.Add` class. """ _cls = crud.Add def test_class(self): + """ + Test the `ipalib.crud.Add` class. + """ assert self.cls.__bases__ == (frontend.Method,) def test_options_args(self): """ - Test `crud.Add.get_args` and `crud.Add.get_options` methods. + Test `ipalib.crud.Add.get_args` and `ipalib.crud.Add.get_options` methods. """ api = get_api() class user_add(self.cls): @@ -70,17 +74,20 @@ class test_Add(ClassChecker): class test_Get(ClassChecker): """ - Test the `crud.Get` class. + Test the `ipalib.crud.Get` class. """ _cls = crud.Get def test_class(self): + """ + Test the `ipalib.crud.Get` class. + """ assert self.cls.__bases__ == (frontend.Method,) def test_options_args(self): """ - Test `crud.Get.get_args` and `crud.Get.get_options` methods. + Test `ipalib.crud.Get.get_args` and `ipalib.crud.Get.get_options` methods. """ api = get_api() class user_get(self.cls): @@ -93,17 +100,20 @@ class test_Get(ClassChecker): class test_Del(ClassChecker): """ - Test the `crud.Del` class. + Test the `ipalib.crud.Del` class. """ _cls = crud.Del def test_class(self): + """ + Test the `ipalib.crud.Del` class. + """ assert self.cls.__bases__ == (frontend.Method,) def test_options_args(self): """ - Test `crud.Del.get_args` and `crud.Del.get_options` methods. + Test `ipalib.crud.Del.get_args` and `ipalib.crud.Del.get_options` methods. """ api = get_api() class user_del(self.cls): @@ -116,17 +126,20 @@ class test_Del(ClassChecker): class test_Mod(ClassChecker): """ - Test the `crud.Mod` class. + Test the `ipalib.crud.Mod` class. """ _cls = crud.Mod def test_class(self): + """ + Test the `ipalib.crud.Mod` class. + """ assert self.cls.__bases__ == (frontend.Method,) def test_options_args(self): """ - Test `crud.Mod.get_args` and `crud.Mod.get_options` methods. + Test `ipalib.crud.Mod.get_args` and `ipalib.crud.Mod.get_options` methods. """ api = get_api() class user_mod(self.cls): @@ -143,17 +156,20 @@ class test_Mod(ClassChecker): class test_Find(ClassChecker): """ - Test the `crud.Find` class. + Test the `ipalib.crud.Find` class. """ _cls = crud.Find def test_class(self): + """ + Test the `ipalib.crud.Find` class. + """ assert self.cls.__bases__ == (frontend.Method,) def test_options_args(self): """ - Test `crud.Find.get_args` and `crud.Find.get_options` methods. + Test `ipalib.crud.Find.get_args` and `ipalib.crud.Find.get_options` methods. """ api = get_api() class user_find(self.cls): -- cgit From 7599beb693b2ab0717299d5d07b17b045b2f7fe3 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 8 Oct 2008 00:17:32 -0600 Subject: Restructured test_crud.py around new CrudChecker base class --- tests/test_ipalib/test_crud.py | 168 ++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 85 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index eb8be643..1e538cc1 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -25,160 +25,158 @@ from tests.util import read_only, raises, ClassChecker from ipalib import crud, frontend, plugable, config -def get_api(): - api = plugable.API( - frontend.Object, - frontend.Method, - frontend.Property, - ) - api.env.update(config.generate_env()) - class user(frontend.Object): - takes_params = ( - 'givenname', - 'sn', - frontend.Param('uid', primary_key=True), - 'initials', +class CrudChecker(ClassChecker): + """ + Class for testing base classes in `ipalib.crud`. + """ + + def get_api(self): + """ + Return a finalized `ipalib.plugable.API` instance. + """ + assert self.cls.__bases__ == (frontend.Method,) + api = plugable.API( + frontend.Object, + frontend.Method, + frontend.Property, ) - api.register(user) - return api + api.env.update(config.generate_env()) + class user(frontend.Object): + takes_params = ( + 'givenname', + 'sn', + frontend.Param('uid', primary_key=True), + 'initials', + ) + class user_verb(self.cls): + pass + api.register(user) + api.register(user_verb) + api.finalize() + return api -class test_Add(ClassChecker): +class test_Add(CrudChecker): """ Test the `ipalib.crud.Add` class. """ _cls = crud.Add - def test_class(self): + def test_get_args(self): """ - Test the `ipalib.crud.Add` class. + Test the `ipalib.crud.Add.get_args` method. """ - assert self.cls.__bases__ == (frontend.Method,) + api = self.get_api() + assert list(api.Method.user_verb.args) == ['uid'] + assert api.Method.user_verb.args.uid.required is True - def test_options_args(self): + def test_get_options(self): """ - Test `ipalib.crud.Add.get_args` and `ipalib.crud.Add.get_options` methods. + Test the `ipalib.crud.Add.get_options` method. """ - api = get_api() - class user_add(self.cls): - pass - api.register(user_add) - api.finalize() - assert list(api.Method.user_add.args) == ['uid'] - assert list(api.Method.user_add.options) == \ + api = self.get_api() + assert list(api.Method.user_verb.options) == \ ['givenname', 'sn', 'initials'] - for param in api.Method.user_add.options(): + for param in api.Method.user_verb.options(): assert param.required is True -class test_Get(ClassChecker): +class test_Get(CrudChecker): """ Test the `ipalib.crud.Get` class. """ _cls = crud.Get - def test_class(self): + def test_get_args(self): """ - Test the `ipalib.crud.Get` class. + Test the `ipalib.crud.Get.get_args` method. """ - assert self.cls.__bases__ == (frontend.Method,) + api = self.get_api() + assert list(api.Method.user_verb.args) == ['uid'] + assert api.Method.user_verb.args.uid.required is True - def test_options_args(self): + def test_get_options(self): """ - Test `ipalib.crud.Get.get_args` and `ipalib.crud.Get.get_options` methods. + Test the `ipalib.crud.Get.get_options` method. """ - api = get_api() - class user_get(self.cls): - pass - api.register(user_get) - api.finalize() - assert list(api.Method.user_get.args) == ['uid'] - assert list(api.Method.user_get.options) == [] + api = self.get_api() + assert list(api.Method.user_verb.options) == [] + assert len(api.Method.user_verb.options) == 0 -class test_Del(ClassChecker): +class test_Del(CrudChecker): """ Test the `ipalib.crud.Del` class. """ _cls = crud.Del - def test_class(self): + def test_get_args(self): """ - Test the `ipalib.crud.Del` class. + Test the `ipalib.crud.Del.get_args` method. """ - assert self.cls.__bases__ == (frontend.Method,) + api = self.get_api() + assert list(api.Method.user_verb.args) == ['uid'] + assert api.Method.user_verb.args.uid.required is True - def test_options_args(self): + def test_get_options(self): """ - Test `ipalib.crud.Del.get_args` and `ipalib.crud.Del.get_options` methods. + Test the `ipalib.crud.Del.get_options` method. """ - api = get_api() - class user_del(self.cls): - pass - api.register(user_del) - api.finalize() - assert list(api.Method.user_del.args) == ['uid'] - assert list(api.Method.user_del.options) == [] + api = self.get_api() + assert list(api.Method.user_verb.options) == [] + assert len(api.Method.user_verb.options) == 0 -class test_Mod(ClassChecker): +class test_Mod(CrudChecker): """ Test the `ipalib.crud.Mod` class. """ _cls = crud.Mod - def test_class(self): + def test_get_args(self): """ - Test the `ipalib.crud.Mod` class. + Test the `ipalib.crud.Mod.get_args` method. """ - assert self.cls.__bases__ == (frontend.Method,) + api = self.get_api() + assert list(api.Method.user_verb.args) == ['uid'] + assert api.Method.user_verb.args.uid.required is True - def test_options_args(self): + def test_get_options(self): """ - Test `ipalib.crud.Mod.get_args` and `ipalib.crud.Mod.get_options` methods. + Test the `ipalib.crud.Mod.get_options` method. """ - api = get_api() - class user_mod(self.cls): - pass - api.register(user_mod) - api.finalize() - assert list(api.Method.user_mod.args) == ['uid'] - assert api.Method.user_mod.args[0].required is True - assert list(api.Method.user_mod.options) == \ + api = self.get_api() + assert list(api.Method.user_verb.options) == \ ['givenname', 'sn', 'initials'] - for param in api.Method.user_mod.options(): + for param in api.Method.user_verb.options(): assert param.required is False -class test_Find(ClassChecker): +class test_Find(CrudChecker): """ Test the `ipalib.crud.Find` class. """ _cls = crud.Find - def test_class(self): + def test_get_args(self): """ - Test the `ipalib.crud.Find` class. + Test the `ipalib.crud.Find.get_args` method. """ - assert self.cls.__bases__ == (frontend.Method,) + api = self.get_api() + assert list(api.Method.user_verb.args) == ['uid'] + assert api.Method.user_verb.args.uid.required is True - def test_options_args(self): + def test_get_options(self): """ - Test `ipalib.crud.Find.get_args` and `ipalib.crud.Find.get_options` methods. + Test the `ipalib.crud.Find.get_options` method. """ - api = get_api() - class user_find(self.cls): - pass - api.register(user_find) - api.finalize() - assert list(api.Method.user_find.args) == ['uid'] - assert api.Method.user_find.args[0].required is True - assert list(api.Method.user_find.options) == \ + api = self.get_api() + assert list(api.Method.user_verb.options) == \ ['givenname', 'sn', 'initials'] - for param in api.Method.user_find.options(): + for param in api.Method.user_verb.options(): assert param.required is False -- cgit From 33648655feffcbab017625683dbfa0bc788ca63b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 8 Oct 2008 00:41:08 -0600 Subject: PEP 257: cleaned up docstrings in test_errors.py --- tests/test_ipalib/test_errors.py | 43 +++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_errors.py b/tests/test_ipalib/test_errors.py index 8db810da..b72d6e02 100644 --- a/tests/test_ipalib/test_errors.py +++ b/tests/test_ipalib/test_errors.py @@ -38,7 +38,7 @@ def check_TypeError(f, value, type_, name, **kw): def test_raise_TypeError(): """ - Tests the `errors.raise_TypeError` function. + Test the `ipalib.errors.raise_TypeError` function. """ f = errors.raise_TypeError value = 'Hello.' @@ -65,7 +65,7 @@ def test_raise_TypeError(): def test_check_type(): """ - Tests the `errors.check_type` function. + Test the `ipalib.errors.check_type` function. """ f = errors.check_type value = 'How are you?' @@ -99,7 +99,7 @@ def test_check_type(): def test_check_isinstance(): """ - Tests the `errors.check_isinstance` function. + Test the `ipalib.errors.check_isinstance` function. """ f = errors.check_isinstance value = 'How are you?' @@ -133,16 +133,19 @@ def test_check_isinstance(): class test_IPAError(ClassChecker): """ - Tests the `errors.IPAError` exception. + Test the `ipalib.errors.IPAError` exception. """ _cls = errors.IPAError def test_class(self): + """ + Test the `ipalib.errors.IPAError` exception. + """ assert self.cls.__bases__ == (Exception,) def test_init(self): """ - Tests the `errors.IPAError.__init__` method. + Test the `ipalib.errors.IPAError.__init__` method. """ args = ('one fish', 'two fish') e = self.cls(*args) @@ -151,7 +154,7 @@ class test_IPAError(ClassChecker): def test_str(self): """ - Tests the `errors.IPAError.__str__` method. + Test the `ipalib.errors.IPAError.__str__` method. """ f = 'The %s color is %s.' class custom_error(self.cls): @@ -164,16 +167,19 @@ class test_IPAError(ClassChecker): class test_ValidationError(ClassChecker): """ - Tests the `errors.ValidationError` exception. + Test the `ipalib.errors.ValidationError` exception. """ _cls = errors.ValidationError def test_class(self): + """ + Test the `ipalib.errors.ValidationError` exception. + """ assert self.cls.__bases__ == (errors.IPAError,) def test_init(self): """ - Tests the `errors.ValidationError.__init__` method. + Test the `ipalib.errors.ValidationError.__init__` method. """ name = 'login' value = 'Whatever' @@ -197,16 +203,19 @@ class test_ValidationError(ClassChecker): class test_ConversionError(ClassChecker): """ - Tests the `errors.ConversionError` exception. + Test the `ipalib.errors.ConversionError` exception. """ _cls = errors.ConversionError def test_class(self): + """ + Test the `ipalib.errors.ConversionError` exception. + """ assert self.cls.__bases__ == (errors.ValidationError,) def test_init(self): """ - Tests the `errors.ConversionError.__init__` method. + Test the `ipalib.errors.ConversionError.__init__` method. """ name = 'some_arg' value = '42.0' @@ -227,16 +236,19 @@ class test_ConversionError(ClassChecker): class test_RuleError(ClassChecker): """ - Tests the `errors.RuleError` exception. + Test the `ipalib.errors.RuleError` exception. """ _cls = errors.RuleError def test_class(self): + """ + Test the `ipalib.errors.RuleError` exception. + """ assert self.cls.__bases__ == (errors.ValidationError,) def test_init(self): """ - Tests the `errors.RuleError.__init__` method. + Test the `ipalib.errors.RuleError.__init__` method. """ name = 'whatever' value = 'The smallest weird number.' @@ -255,16 +267,19 @@ class test_RuleError(ClassChecker): class test_RequirementError(ClassChecker): """ - Tests the `errors.RequirementError` exception. + Test the `ipalib.errors.RequirementError` exception. """ _cls = errors.RequirementError def test_class(self): + """ + Test the `ipalib.errors.RequirementError` exception. + """ assert self.cls.__bases__ == (errors.ValidationError,) def test_init(self): """ - Tests the `errors.RequirementError.__init__` method. + Test the `ipalib.errors.RequirementError.__init__` method. """ name = 'givenname' e = self.cls(name) -- cgit From ad2cd6560b9fb45ee1b8c52213f3d36eac70bec7 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 8 Oct 2008 00:58:53 -0600 Subject: PEP 257: cleaned up docstrings in test_frontend.py --- tests/test_ipalib/test_frontend.py | 121 +++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 45 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 4b1b56cf..b798d2ee 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -21,8 +21,8 @@ Test the `ipalib.frontend` module. """ -from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker -from tests.util import check_TypeError +from tests.util import raises, getitem, no_set, no_del, read_only +from tests.util import check_TypeError, ClassChecker from ipalib import frontend, backend, plugable, errors, ipa_types, config @@ -32,7 +32,7 @@ def test_RULE_FLAG(): def test_rule(): """ - Tests the `frontend.rule` function. + Test the `ipalib.frontend.rule` function. """ flag = frontend.RULE_FLAG rule = frontend.rule @@ -49,7 +49,7 @@ def test_rule(): def test_is_rule(): """ - Tests the `frontend.is_rule` function. + Test the `ipalib.frontend.is_rule` function. """ is_rule = frontend.is_rule flag = frontend.RULE_FLAG @@ -72,16 +72,19 @@ def test_is_rule(): class test_DefaultFrom(ClassChecker): """ - Tests the `frontend.DefaultFrom` class. + 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): """ - Tests the `frontend.DefaultFrom.__init__` method. + Test the `ipalib.frontend.DefaultFrom.__init__` method. """ def callback(*args): return args @@ -95,7 +98,7 @@ class test_DefaultFrom(ClassChecker): def test_call(self): """ - Tests the `frontend.DefaultFrom.__call__` method. + Test the `ipalib.frontend.DefaultFrom.__call__` method. """ def callback(givenname, sn): return givenname[0] + sn[0] @@ -120,7 +123,7 @@ class test_DefaultFrom(ClassChecker): def test_parse_param_spec(): """ - Test the `frontend.parse_param_spec` function. + Test the `ipalib.frontend.parse_param_spec` function. """ f = frontend.parse_param_spec @@ -132,16 +135,19 @@ def test_parse_param_spec(): class test_Param(ClassChecker): """ - Test the `frontend.Param` class. + 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 `frontend.Param.__init__` method. + Test the `ipalib.frontend.Param.__init__` method. """ name = 'sn' o = self.cls(name) @@ -207,7 +213,7 @@ class test_Param(ClassChecker): def test_clone(self): """ - Test the `frontend.Param.__clone__` method. + Test the `ipalib.frontend.Param.__clone__` method. """ def compare(o, kw): for (k, v) in kw.iteritems(): @@ -234,7 +240,7 @@ class test_Param(ClassChecker): def test_convert(self): """ - Test the `frontend.Param.convert` method. + Test the `ipalib.frontend.Param.convert` method. """ name = 'some_number' type_ = ipa_types.Int() @@ -279,7 +285,7 @@ class test_Param(ClassChecker): def test_normalize(self): """ - Test the `frontend.Param.normalize` method. + Test the `ipalib.frontend.Param.normalize` method. """ name = 'sn' callback = lambda value: value.lower() @@ -321,7 +327,7 @@ class test_Param(ClassChecker): def test_validate(self): """ - Tests the `frontend.Param.validate` method. + Test the `ipalib.frontend.Param.validate` method. """ name = 'sn' type_ = ipa_types.Unicode() @@ -367,7 +373,7 @@ class test_Param(ClassChecker): def test_get_default(self): """ - Tests the `frontend.Param.get_default` method. + Test the `ipalib.frontend.Param.get_default` method. """ name = 'greeting' default = u'Hello, world!' @@ -400,7 +406,7 @@ class test_Param(ClassChecker): def test_get_value(self): """ - Tests the `frontend.Param.get_values` method. + Test the `ipalib.frontend.Param.get_values` method. """ name = 'status' values = (u'Active', u'Inactive') @@ -412,7 +418,7 @@ class test_Param(ClassChecker): def test_create_param(): """ - Test the `frontend.create_param` function. + Test the `ipalib.frontend.create_param` function. """ f = frontend.create_param for name in ['arg', 'arg?', 'arg*', 'arg+']: @@ -437,11 +443,15 @@ def test_create_param(): class test_Command(ClassChecker): """ - Tests the `frontend.Command` class. + Test the `ipalib.frontend.Command` class. """ + _cls = frontend.Command def get_subcls(self): + """ + Return a standard subclass of `ipalib.frontend.Command`. + """ class Rule(object): def __init__(self, name): self.name = name @@ -484,13 +494,16 @@ class test_Command(ClassChecker): return o def test_class(self): + """ + Test the `ipalib.frontend.Command` class. + """ assert self.cls.__bases__ == (plugable.Plugin,) assert self.cls.takes_options == tuple() assert self.cls.takes_args == tuple() def test_get_args(self): """ - Tests the `frontend.Command.get_args` method. + Test the `ipalib.frontend.Command.get_args` method. """ assert list(self.cls().get_args()) == [] args = ('login', 'stuff') @@ -499,7 +512,7 @@ class test_Command(ClassChecker): def test_get_options(self): """ - Tests the `frontend.Command.get_options` method. + Test the `ipalib.frontend.Command.get_options` method. """ assert list(self.cls().get_options()) == [] options = ('verbose', 'debug') @@ -508,7 +521,7 @@ class test_Command(ClassChecker): def test_args(self): """ - Tests the ``Command.args`` instance attribute. + Test the ``ipalib.frontend.Command.args`` instance attribute. """ assert 'args' in self.cls.__public__ # Public assert self.cls().args is None @@ -543,7 +556,7 @@ class test_Command(ClassChecker): def test_max_args(self): """ - Test the ``Command.max_args`` instance attribute. + Test the ``ipalib.frontend.Command.max_args`` instance attribute. """ o = self.get_instance() assert o.max_args == 0 @@ -558,7 +571,7 @@ class test_Command(ClassChecker): def test_options(self): """ - Tests the ``Command.options`` instance attribute. + Test the ``ipalib.frontend.Command.options`` instance attribute. """ assert 'options' in self.cls.__public__ # Public assert self.cls().options is None @@ -580,7 +593,7 @@ class test_Command(ClassChecker): def test_convert(self): """ - Tests the `frontend.Command.convert` method. + Test the `ipalib.frontend.Command.convert` method. """ assert 'convert' in self.cls.__public__ # Public kw = dict( @@ -598,7 +611,7 @@ class test_Command(ClassChecker): def test_normalize(self): """ - Tests the `frontend.Command.normalize` method. + Test the `ipalib.frontend.Command.normalize` method. """ assert 'normalize' in self.cls.__public__ # Public kw = dict( @@ -612,7 +625,7 @@ class test_Command(ClassChecker): def test_get_default(self): """ - Tests the `frontend.Command.get_default` method. + Test the `ipalib.frontend.Command.get_default` method. """ assert 'get_default' in self.cls.__public__ # Public no_fill = dict( @@ -634,7 +647,7 @@ class test_Command(ClassChecker): def test_validate(self): """ - Tests the `frontend.Command.validate` method. + Test the `ipalib.frontend.Command.validate` method. """ assert 'validate' in self.cls.__public__ # Public @@ -669,13 +682,13 @@ class test_Command(ClassChecker): def test_execute(self): """ - Tests the `frontend.Command.execute` method. + Test the `ipalib.frontend.Command.execute` method. """ assert 'execute' in self.cls.__public__ # Public def test_args_to_kw(self): """ - Test the `frontend.Command.args_to_kw` method. + Test the `ipalib.frontend.Command.args_to_kw` method. """ assert 'args_to_kw' in self.cls.__public__ # Public o = self.get_instance(args=('one', 'two?')) @@ -706,7 +719,7 @@ class test_Command(ClassChecker): def test_kw_to_args(self): """ - Tests the `frontend.Command.kw_to_args` method. + Test the `ipalib.frontend.Command.kw_to_args` method. """ assert 'kw_to_args' in self.cls.__public__ # Public o = self.get_instance(args=('one', 'two?')) @@ -719,7 +732,7 @@ class test_Command(ClassChecker): def test_run(self): """ - Test the `frontend.Command.run` method. + Test the `ipalib.frontend.Command.run` method. """ class my_cmd(self.cls): def execute(self, *args, **kw): @@ -754,11 +767,14 @@ class test_Command(ClassChecker): class test_Object(ClassChecker): """ - Test the `frontend.Object` class. + Test the `ipalib.frontend.Object` class. """ _cls = frontend.Object def test_class(self): + """ + Test the `ipalib.frontend.Object` class. + """ assert self.cls.__bases__ == (plugable.Plugin,) assert self.cls.backend is None assert self.cls.methods is None @@ -769,7 +785,7 @@ class test_Object(ClassChecker): def test_init(self): """ - Test the `frontend.Object.__init__` method. + Test the `ipalib.frontend.Object.__init__` method. """ o = self.cls() assert o.backend is None @@ -781,7 +797,7 @@ class test_Object(ClassChecker): def test_set_api(self): """ - Test the `frontend.Object.set_api` method. + Test the `ipalib.frontend.Object.set_api` method. """ # Setup for test: class DummyAttribute(object): @@ -867,7 +883,7 @@ class test_Object(ClassChecker): def test_primary_key(self): """ - Test the `frontend.Object.primary_key` attribute. + Test the `ipalib.frontend.Object.primary_key` attribute. """ api = plugable.API( frontend.Method, @@ -922,7 +938,7 @@ class test_Object(ClassChecker): def test_backend(self): """ - Test the `frontend.Object.backend` attribute. + Test the `ipalib.frontend.Object.backend` attribute. """ api = plugable.API( frontend.Object, @@ -945,11 +961,14 @@ class test_Object(ClassChecker): class test_Attribute(ClassChecker): """ - Tests the `frontend.Attribute` class. + Test the `ipalib.frontend.Attribute` class. """ _cls = frontend.Attribute def test_class(self): + """ + Test the `ipalib.frontend.Attribute` class. + """ assert self.cls.__bases__ == (plugable.Plugin,) assert type(self.cls.obj) is property assert type(self.cls.obj_name) is property @@ -957,7 +976,7 @@ class test_Attribute(ClassChecker): def test_init(self): """ - Tests the `frontend.Attribute.__init__` method. + Test the `ipalib.frontend.Attribute.__init__` method. """ class user_add(self.cls): pass @@ -968,7 +987,7 @@ class test_Attribute(ClassChecker): def test_set_api(self): """ - Tests the `frontend.Attribute.set_api` method. + Test the `ipalib.frontend.Attribute.set_api` method. """ user_obj = 'The user frontend.Object instance' class api(object): @@ -985,18 +1004,21 @@ class test_Attribute(ClassChecker): class test_Method(ClassChecker): """ - Test the `frontend.Method` class. + Test the `ipalib.frontend.Method` class. """ _cls = frontend.Method def test_class(self): + """ + Test the `ipalib.frontend.Method` class. + """ assert self.cls.__bases__ == (frontend.Attribute, frontend.Command) assert self.cls.implements(frontend.Command) assert self.cls.implements(frontend.Attribute) def test_init(self): """ - Test the `frontend.Method.__init__` method. + Test the `ipalib.frontend.Method.__init__` method. """ class user_add(self.cls): pass @@ -1010,11 +1032,14 @@ class test_Method(ClassChecker): class test_Property(ClassChecker): """ - Tests the `frontend.Property` class. + Test the `ipalib.frontend.Property` class. """ _cls = frontend.Property def get_subcls(self): + """ + Return a standard subclass of `ipalib.frontend.Property`. + """ class user_givenname(self.cls): 'User first name' @@ -1025,6 +1050,9 @@ class test_Property(ClassChecker): return user_givenname def test_class(self): + """ + 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 @@ -1035,7 +1063,7 @@ class test_Property(ClassChecker): def test_init(self): """ - Tests the `frontend.Property.__init__` method. + Test the `ipalib.frontend.Property.__init__` method. """ o = self.subcls() assert len(o.rules) == 1 @@ -1048,17 +1076,20 @@ class test_Property(ClassChecker): class test_Application(ClassChecker): """ - Tests the `frontend.Application` class. + Test the `ipalib.frontend.Application` class. """ _cls = frontend.Application def test_class(self): + """ + Test the `ipalib.frontend.Application` class. + """ assert self.cls.__bases__ == (frontend.Command,) assert type(self.cls.application) is property def test_application(self): """ - Tests the `frontend.Application.application` property. + Test the `ipalib.frontend.Application.application` property. """ assert 'application' in self.cls.__public__ # Public assert 'set_application' in self.cls.__public__ # Public -- cgit From 048678fc774bace19687976133d296a168488c59 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 8 Oct 2008 01:00:44 -0600 Subject: Fixed two PEP 257 violations I missed in test_plugable.py --- tests/test_ipalib/test_plugable.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 3cdf1808..dec893a9 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -231,13 +231,13 @@ class test_DictProxy(ClassChecker): class test_MagicDict(ClassChecker): """ - Tests the `ipalib.plugable.MagicDict` class. + Test the `ipalib.plugable.MagicDict` class. """ _cls = plugable.MagicDict def test_class(self): """ - Tests the `ipalib.plugable.MagicDict` class. + Test the `ipalib.plugable.MagicDict` class. """ assert self.cls.__bases__ == (plugable.DictProxy,) for non_dict in ('hello', 69, object): -- cgit From b246dbabcffa664a4f4f59ea800ad8a26e2c81dd Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 8 Oct 2008 01:24:39 -0600 Subject: PEP 257: cleaned up docstrings in test_ipa_types.py --- tests/test_ipalib/test_ipa_types.py | 65 +++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_ipa_types.py b/tests/test_ipalib/test_ipa_types.py index 65d1f63d..eb166069 100644 --- a/tests/test_ipalib/test_ipa_types.py +++ b/tests/test_ipalib/test_ipa_types.py @@ -27,7 +27,7 @@ from ipalib import ipa_types, errors, plugable def test_check_min_max(): """ - Tests the `ipa_types.check_min_max` function. + Test the `ipalib.ipa_types.check_min_max` function. """ f = ipa_types.check_min_max okay = [ @@ -62,14 +62,20 @@ def test_check_min_max(): class test_Type(ClassChecker): """ - Tests the `ipa_types.Type` class. + 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) @@ -88,18 +94,30 @@ class test_Type(ClassChecker): 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 @@ -122,6 +140,9 @@ class test_Bool(ClassChecker): 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 @@ -133,12 +154,21 @@ class test_Bool(ClassChecker): 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 @@ -186,6 +216,9 @@ class test_Int(ClassChecker): ) def test_call(self): + """ + Test the `ipalib.ipa_types.Int.__call__` method. + """ o = self.cls() # Test calling with None @@ -213,8 +246,10 @@ class test_Int(ClassChecker): 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 @@ -226,12 +261,21 @@ class test_Int(ClassChecker): 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 @@ -318,6 +362,9 @@ class test_Unicode(ClassChecker): 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 @@ -330,12 +377,21 @@ class test_Unicode(ClassChecker): 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) @@ -361,6 +417,9 @@ class test_Enum(ClassChecker): 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: -- cgit From bc9edbfdf6a4d0d3b0f6c0b4c6ea82b24be27806 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 8 Oct 2008 01:30:52 -0600 Subject: Changed sub-package docstrings in tests/ to make consintent with other packages --- tests/test_ipalib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/__init__.py b/tests/test_ipalib/__init__.py index b12bccc5..113881eb 100644 --- a/tests/test_ipalib/__init__.py +++ b/tests/test_ipalib/__init__.py @@ -18,5 +18,5 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Test the `ipalib` package. +Sub-package containing unit tests for `ipalib` package. """ -- cgit From 887016e69d6678892a2ff53735623ce5d413b074 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 8 Oct 2008 18:18:13 -0600 Subject: Base Command.execute() method now raises NotImplementedError; updated unit tests --- tests/test_ipalib/test_frontend.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index b798d2ee..89b77ad7 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -685,6 +685,9 @@ class test_Command(ClassChecker): Test the `ipalib.frontend.Command.execute` method. """ assert 'execute' in self.cls.__public__ # Public + o = self.cls() + e = raises(NotImplementedError, o.execute) + assert str(e) == 'Command.execute()' def test_args_to_kw(self): """ -- cgit From 87390665f6998116ec2429773088c7165e281611 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 9 Oct 2008 11:33:35 -0600 Subject: crud.Add.get_args() and get_options() now yield static values in takes_args, takes_options after the automagic ones --- tests/test_ipalib/test_crud.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index 1e538cc1..37da503b 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -30,7 +30,7 @@ class CrudChecker(ClassChecker): Class for testing base classes in `ipalib.crud`. """ - def get_api(self): + def get_api(self, args=tuple(), options={}): """ Return a finalized `ipalib.plugable.API` instance. """ @@ -49,7 +49,8 @@ class CrudChecker(ClassChecker): 'initials', ) class user_verb(self.cls): - pass + takes_args = args + takes_options = options api.register(user) api.register(user_verb) api.finalize() @@ -70,6 +71,10 @@ class test_Add(CrudChecker): api = self.get_api() assert list(api.Method.user_verb.args) == ['uid'] assert api.Method.user_verb.args.uid.required is True + api = self.get_api(args=('extra?',)) + assert list(api.Method.user_verb.args) == ['uid', 'extra'] + assert api.Method.user_verb.args.uid.required is True + assert api.Method.user_verb.args.extra.required is False def test_get_options(self): """ @@ -80,6 +85,10 @@ class test_Add(CrudChecker): ['givenname', 'sn', 'initials'] for param in api.Method.user_verb.options(): assert param.required is True + api = self.get_api(options=('extra?',)) + assert list(api.Method.user_verb.options) == \ + ['givenname', 'sn', 'initials', 'extra'] + assert api.Method.user_verb.options.extra.required is False class test_Get(CrudChecker): -- cgit From 225e2b0c939d81b490c955762e125e8afcd5bb94 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 13 Oct 2008 09:50:29 -0600 Subject: Added CrudBackend abstract class defining generic CRUD API --- tests/test_ipalib/test_crud.py | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index 37da503b..d7e6b51f 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -189,3 +189,54 @@ class test_Find(CrudChecker): ['givenname', 'sn', 'initials'] for param in api.Method.user_verb.options(): assert param.required is False + + +class test_CrudBackend(ClassChecker): + """ + Test the `ipalib.crud.CrudBackend` class. + """ + + _cls = crud.CrudBackend + + def get_subcls(self): + class ldap(self.cls): + pass + return ldap + + def check_method(self, name, *args): + o = self.cls() + e = raises(NotImplementedError, getattr(o, name), *args) + assert str(e) == 'CrudBackend.%s()' % name + sub = self.subcls() + e = raises(NotImplementedError, getattr(sub, name), *args) + assert str(e) == 'ldap.%s()' % name + + def test_create(self): + """ + Test the `ipalib.crud.CrudBackend.create` method. + """ + self.check_method('create') + + def test_retrieve(self): + """ + Test the `ipalib.crud.CrudBackend.retrieve` method. + """ + self.check_method('retrieve', 'primary key') + + def test_update(self): + """ + Test the `ipalib.crud.CrudBackend.update` method. + """ + self.check_method('update', 'primary key') + + def test_delete(self): + """ + Test the `ipalib.crud.CrudBackend.delete` method. + """ + self.check_method('delete', 'primary key') + + def test_search(self): + """ + Test the `ipalib.crud.CrudBackend.search` method. + """ + self.check_method('search') -- cgit From 8674086b8536f64947ca8cdb97d7a1cd3bf1c684 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 13 Oct 2008 17:24:23 -0600 Subject: Param now takes cli_name kwarg that sets Param.cli_name attribute --- tests/test_ipalib/test_frontend.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 89b77ad7..297aa8da 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -155,6 +155,7 @@ class test_Param(ClassChecker): # 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 @@ -167,6 +168,7 @@ class test_Param(ClassChecker): # 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 -- cgit From 446037fd60d59f671b9a402b9111ab041c1c1439 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 13 Oct 2008 23:26:24 -0600 Subject: Added Object.get_dn() method; added corresponding unit tests --- tests/test_ipalib/test_frontend.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 297aa8da..9ab0504b 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -963,6 +963,20 @@ class test_Object(ClassChecker): assert isinstance(b, ldap) assert b.whatever == 'It worked!' + def test_get_dn(self): + """ + Test the `ipalib.frontend.Object.get_dn` method. + """ + assert 'get_dn' in self.cls.__public__ # Public + o = self.cls() + e = raises(NotImplementedError, o.get_dn, 'primary key') + assert str(e) == 'Object.get_dn()' + class user(self.cls): + pass + o = user() + e = raises(NotImplementedError, o.get_dn, 'primary key') + assert str(e) == 'user.get_dn()' + class test_Attribute(ClassChecker): """ -- cgit From ff88652a405c7fd9236a9b1d80dd8955a9ca056d Mon Sep 17 00:00:00 2001 From: Martin Nagy Date: Tue, 14 Oct 2008 21:22:44 +0200 Subject: Convert string values to boolean when generating environment --- tests/test_ipalib/test_config.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 2ec75048..3fe44136 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -37,8 +37,11 @@ def test_generate_env(): query_dns = False, server = ('first', 'second'), realm = 'myrealm', + # test right conversions + server_context = 'off', ) d = config.generate_env(env) + assert d['server_context'] == False assert d['query_dns'] == False # Make sure the servers is overwrote properly (that it is still LazyProp) -- cgit From 3a80297b04d6fbfd2367ec76c5651d20293adccc Mon Sep 17 00:00:00 2001 From: Martin Nagy Date: Fri, 17 Oct 2008 22:55:03 +0200 Subject: Reworking Environment, moved it to config.py --- tests/test_ipalib/test_config.py | 106 ++++++++++++++++++++++++++++++++----- tests/test_ipalib/test_crud.py | 2 +- tests/test_ipalib/test_frontend.py | 4 +- tests/test_ipalib/test_plugable.py | 79 --------------------------- 4 files changed, 97 insertions(+), 94 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 3fe44136..df830232 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -23,29 +23,111 @@ Test the `ipalib.config` module. import types -from tests.util import raises +from tests.util import raises, setitem, delitem +#from tests.util import getitem, setitem, delitem from ipalib import config -def test_generate_env(): +def test_Environment(): """ - Test the `ipalib.config.generate_env` function. + Test the `ipalib.config.Environment` class. + """ + # This has to be the same as iter_cnt + control_cnt = 0 + class prop_class: + def __init__(self, val): + self._val = val + def get_value(self): + return self._val + + class iter_class(prop_class): + # Increment this for each time iter_class yields + iter_cnt = 0 + def get_value(self): + for item in self._val: + self.__class__.iter_cnt += 1 + yield item + + # Tests for basic functionality + basic_tests = ( + ('a', 1), + ('b', 'basic_foo'), + ('c', ('basic_bar', 'basic_baz')), + ) + # Tests with prop classes + prop_tests = ( + ('d', prop_class(2), 2), + ('e', prop_class('prop_foo'), 'prop_foo'), + ('f', prop_class(('prop_bar', 'prop_baz')), ('prop_bar', 'prop_baz')), + ) + # Tests with iter classes + iter_tests = ( + ('g', iter_class((3, 4, 5)), (3, 4, 5)), + ('h', iter_class(('iter_foo', 'iter_bar', 'iter_baz')), + ('iter_foo', 'iter_bar', 'iter_baz') + ), + ) + + # Set all the values + env = config.Environment() + for name, val in basic_tests: + env[name] = val + for name, val, dummy in prop_tests: + env[name] = val + for name, val, dummy in iter_tests: + env[name] = val + + # Test if the values are correct + for name, val in basic_tests: + assert env[name] == val + for name, dummy, val in prop_tests: + assert env[name] == val + # Test if the get_value() function is called only when needed + for name, dummy, correct_values in iter_tests: + values_in_env = [] + for val in env[name]: + control_cnt += 1 + assert iter_class.iter_cnt == control_cnt + values_in_env.append(val) + assert tuple(values_in_env) == correct_values + + # Test __setattr__() + env.spam = 'ham' + assert env.spam == 'ham' + + # Test if we throw AttributeError exception when trying to overwrite + # existing value, or delete it + raises(AttributeError, setitem, env, 'a', 1) + raises(AttributeError, setattr, env, 'a', 1) + raises(AttributeError, delitem, env, 'a') + raises(AttributeError, delattr, env, 'a') + raises(AttributeError, config.Environment.update, env, dict(a=1000)) + # This should be silently ignored + env.update(dict(a=1000), True) + assert env.a != 1000 + + +def test_set_default_env(): + """ + Test the `ipalib.config.set_default_env` function. """ # Make sure we don't overwrite any properties - env = dict( + d = dict( query_dns = False, server = ('first', 'second'), realm = 'myrealm', # test right conversions server_context = 'off', ) - d = config.generate_env(env) - assert d['server_context'] == False - assert d['query_dns'] == False + env = config.Environment() + config.set_default_env(env) + env.update(d) + assert env['server_context'] == False + assert env['query_dns'] == False # Make sure the servers is overwrote properly (that it is still LazyProp) - iter = d['server'].get_value() + iter = env['server'] assert iter.next() == 'first' assert iter.next() == 'second' @@ -59,13 +141,13 @@ def test_LazyProp(): return 1 # Basic sanity testing with no initial value - prop = config.LazyProp(dummy) + prop = config.LazyProp(int, dummy) assert prop.get_value() == 1 prop.set_value(2) assert prop.get_value() == 2 # Basic sanity testing with initial value - prop = config.LazyProp(dummy, 3) + prop = config.LazyProp(int, dummy, 3) assert prop.get_value() == 3 prop.set_value(4) assert prop.get_value() == 4 @@ -81,14 +163,14 @@ def test_LazyIter(): yield 2 # Basic sanity testing with no initial value - prop = config.LazyIter(dummy) + prop = config.LazyIter(int, dummy) iter = prop.get_value() assert iter.next() == 1 assert iter.next() == 2 raises(StopIteration, iter.next) # Basic sanity testing with initial value - prop = config.LazyIter(dummy, 0) + prop = config.LazyIter(int, dummy, 0) iter = prop.get_value() assert iter.next() == 0 assert iter.next() == 1 diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index d7e6b51f..9a207cce 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -40,7 +40,7 @@ class CrudChecker(ClassChecker): frontend.Method, frontend.Property, ) - api.env.update(config.generate_env()) + config.set_default_env(api.env) class user(frontend.Object): takes_params = ( 'givenname', diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 9ab0504b..c5742886 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -894,7 +894,7 @@ class test_Object(ClassChecker): frontend.Method, frontend.Property, ) - api.env.update(config.generate_env()) + config.set_default_env(api.env) api.finalize() # Test with no primary keys: @@ -951,7 +951,7 @@ class test_Object(ClassChecker): frontend.Property, backend.Backend, ) - api.env.update(config.generate_env()) + config.set_default_env(api.env) class ldap(backend.Backend): whatever = 'It worked!' api.register(ldap) diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index dec893a9..61011797 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -659,85 +659,6 @@ class test_NameSpace(ClassChecker): 'NameSpace(<%d members>, sort=%r)' % (cnt, sort) -def test_Environment(): - """ - Test the `ipalib.plugable.Environment` class. - """ - # This has to be the same as iter_cnt - control_cnt = 0 - class prop_class: - def __init__(self, val): - self._val = val - def get_value(self): - return self._val - - class iter_class(prop_class): - # Increment this for each time iter_class yields - iter_cnt = 0 - def get_value(self): - for item in self._val: - self.__class__.iter_cnt += 1 - yield item - - # Tests for basic functionality - basic_tests = ( - ('a', 1), - ('b', 'basic_foo'), - ('c', ('basic_bar', 'basic_baz')), - ) - # Tests with prop classes - prop_tests = ( - ('d', prop_class(2), 2), - ('e', prop_class('prop_foo'), 'prop_foo'), - ('f', prop_class(('prop_bar', 'prop_baz')), ('prop_bar', 'prop_baz')), - ) - # Tests with iter classes - iter_tests = ( - ('g', iter_class((3, 4, 5)), (3, 4, 5)), - ('h', iter_class(('iter_foo', 'iter_bar', 'iter_baz')), - ('iter_foo', 'iter_bar', 'iter_baz') - ), - ) - - # Set all the values - env = plugable.Environment() - for name, val in basic_tests: - env[name] = val - for name, val, dummy in prop_tests: - env[name] = val - for name, val, dummy in iter_tests: - env[name] = val - - # Test if the values are correct - for name, val in basic_tests: - assert env[name] == val - for name, dummy, val in prop_tests: - assert env[name] == val - # Test if the get_value() function is called only when needed - for name, dummy, correct_values in iter_tests: - values_in_env = [] - for val in env[name]: - control_cnt += 1 - assert iter_class.iter_cnt == control_cnt - values_in_env.append(val) - assert tuple(values_in_env) == correct_values - - # Test __setattr__() - env.spam = 'ham' - assert env.spam == 'ham' - - # Test if we throw AttributeError exception when trying to overwrite - # existing value, or delete it - raises(AttributeError, setitem, env, 'a', 1) - raises(AttributeError, setattr, env, 'a', 1) - raises(AttributeError, delitem, env, 'a') - raises(AttributeError, delattr, env, 'a') - raises(AttributeError, plugable.Environment.update, env, dict(a=1000)) - # This should be silently ignored - env.update(dict(a=1000), True) - assert env.a != 1000 - - def test_Registrar(): """ Test the `ipalib.plugable.Registrar` class -- cgit From 1be301821e7596d2db7e5b8e81d75ae1c6dab7f1 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 17 Oct 2008 16:47:09 -0600 Subject: Fixed unit test for CrudBacked.retrieve() --- tests/test_ipalib/test_crud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index 9a207cce..794921aa 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -221,7 +221,7 @@ class test_CrudBackend(ClassChecker): """ Test the `ipalib.crud.CrudBackend.retrieve` method. """ - self.check_method('retrieve', 'primary key') + self.check_method('retrieve', 'primary key', 'attribute') def test_update(self): """ -- cgit From 8322138f38a4f9c826e4ab148a4fee7df5e93b34 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 17 Oct 2008 19:34:26 -0600 Subject: Added new Param.flags attribute (set with flags=foo kwarg) --- tests/test_ipalib/test_frontend.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index c5742886..7760ffbe 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -162,6 +162,7 @@ class test_Param(ClassChecker): 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 @@ -183,6 +184,8 @@ class test_Param(ClassChecker): 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 -- cgit From 18e74643a6979ca4e490d34975a38c83a1722417 Mon Sep 17 00:00:00 2001 From: Martin Nagy Date: Mon, 20 Oct 2008 19:53:07 +0200 Subject: Add comments in config.py and fix Environment.get() --- tests/test_ipalib/test_config.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index df830232..ed982a73 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -93,7 +93,12 @@ def test_Environment(): # Test __setattr__() env.spam = 'ham' + assert env.spam == 'ham' + assert env['spam'] == 'ham' + assert env.get('spam') == 'ham' + assert env.get('nonexistent') == None + assert env.get('nonexistent', 42) == 42 # Test if we throw AttributeError exception when trying to overwrite # existing value, or delete it -- cgit From bb978e591b08b3388345c848fb866c22239094ac Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 20 Oct 2008 16:45:32 -0600 Subject: Fixed bug in DefaultFrom where impleied keys were using entire func_code.co_varnames instead of an approprate slice --- tests/test_ipalib/test_frontend.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 7760ffbe..966b5e93 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -115,11 +115,21 @@ class test_DefaultFrom(ClassChecker): 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(): """ -- cgit From 59a2cffff45499e1898ebbc7b76ede12d848addb Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 23 Oct 2008 21:21:51 -0600 Subject: IPAError now more appropriately subclasses from StandardError instead of Exception --- tests/test_ipalib/test_errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_errors.py b/tests/test_ipalib/test_errors.py index b72d6e02..f1dd5dc8 100644 --- a/tests/test_ipalib/test_errors.py +++ b/tests/test_ipalib/test_errors.py @@ -141,7 +141,7 @@ class test_IPAError(ClassChecker): """ Test the `ipalib.errors.IPAError` exception. """ - assert self.cls.__bases__ == (Exception,) + assert self.cls.__bases__ == (StandardError,) def test_init(self): """ -- cgit From 2ec0312eb6d4131fe22fab6f4409b71cac83f98f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 24 Oct 2008 01:51:36 -0600 Subject: Finished doodle with stricter version of Environment --- tests/test_ipalib/test_config.py | 122 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index ed982a73..fa497206 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -23,8 +23,8 @@ Test the `ipalib.config` module. import types -from tests.util import raises, setitem, delitem -#from tests.util import getitem, setitem, delitem +from tests.util import raises, setitem, delitem, ClassChecker +from tests.util import getitem, setitem, delitem from ipalib import config @@ -112,6 +112,124 @@ def test_Environment(): assert env.a != 1000 +class test_Env(ClassChecker): + """ + Test the `ipalib.config.Env` class. + """ + + _cls = config.Env + + def test_init(self): + """ + Test the `ipalib.config.Env.__init__` method. + """ + o = self.cls() + + def test_lock(self): + """ + Test the `ipalib.config.Env.__lock__` method. + """ + o = self.cls() + assert o._Env__locked is False + o.__lock__() + assert o._Env__locked is True + e = raises(StandardError, o.__lock__) + assert str(e) == 'Env.__lock__() already called' + + def test_getattr(self): + """ + Test the `ipalib.config.Env.__getattr__` method. + + Also tests the `ipalib.config.Env.__getitem__` method. + """ + o = self.cls() + value = 'some value' + o.key = value + assert o.key is value + assert o['key'] is value + o.call = lambda: 'whatever' + assert o.call == 'whatever' + assert o['call'] == 'whatever' + for name in ('one', 'two'): + e = raises(AttributeError, getattr, o, name) + assert str(e) == 'Env.%s' % name + e = raises(KeyError, getitem, o, name) + assert str(e) == repr(name) + + def test_setattr(self): + """ + Test the `ipalib.config.Env.__setattr__` method. + + Also tests the `ipalib.config.Env.__setitem__` method. + """ + items = [ + ('one', 1), + ('two', lambda: 2), + ('three', 3), + ('four', lambda: 4), + ] + for setvar in (setattr, setitem): + o = self.cls() + for (i, (name, value)) in enumerate(items): + setvar(o, name, value) + assert getattr(o, name) == i + 1 + assert o[name] == i + 1 + if callable(value): + assert name not in dir(o) + else: + assert name in dir(o) + e = raises(AttributeError, setvar, o, name, 42) + assert str(e) == 'cannot overwrite Env.%s with 42' % name + o = self.cls() + o.__lock__() + for (name, value) in items: + e = raises(AttributeError, setvar, o, name, value) + assert str(e) == \ + 'locked: cannot set Env.%s to %r' % (name, value) + + def test_delattr(self): + """ + Test the `ipalib.config.Env.__delattr__` method. + + This also tests that ``__delitem__`` is not implemented. + """ + o = self.cls() + o.one = 1 + assert o.one == 1 + for key in ('one', 'two'): + e = raises(AttributeError, delattr, o, key) + assert str(e) == 'cannot del Env.%s' % key + e = raises(AttributeError, delitem, o, key) + assert str(e) == '__delitem__' + + def test_contains(self): + """ + Test the `ipalib.config.Env.__contains__` method. + """ + o = self.cls() + items = [ + ('one', 1), + ('two', lambda: 2), + ('three', 3), + ('four', lambda: 4), + ] + for (key, value) in items: + assert key not in o + o[key] = value + assert key in o + + def test_iter(self): + """ + Test the `ipalib.config.Env.__iter__` method. + """ + o = self.cls() + assert list(o) == [] + keys = ('one', 'two', 'three', 'four', 'five') + for key in keys: + o[key] = 'the value' + assert list(o) == sorted(keys) + + def test_set_default_env(): """ Test the `ipalib.config.set_default_env` function. -- cgit From f80beb948bb8914df922e85ef20d9152ca47b527 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 24 Oct 2008 15:07:07 -0600 Subject: Added ipalib/constants.py; added Env._load_config() method along with comprehensive unit tests for same --- tests/test_ipalib/test_config.py | 185 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index fa497206..39dc7906 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -22,9 +22,12 @@ Test the `ipalib.config` module. """ import types - +import os +from os import path +import sys from tests.util import raises, setitem, delitem, ClassChecker from tests.util import getitem, setitem, delitem +from tests.util import TempDir from ipalib import config @@ -112,6 +115,65 @@ def test_Environment(): assert env.a != 1000 +# Random base64-encoded data to simulate a misbehaving config file. +config_bad = """ +/9j/4AAQSkZJRgABAQEAlgCWAAD//gAIT2xpdmVy/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgx +IyUdKDozPTw5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/8AACwgAlgB0AQERAP/E +ABsAAAEFAQEAAAAAAAAAAAAAAAQAAQIDBQYH/8QAMhAAAgICAAUDBAIABAcAAAAAAQIAAwQRBRIh +MUEGE1EiMmFxFIEVI0LBFjNSYnKRof/aAAgBAQAAPwDCtzmNRr1o/MEP1D6f7kdkRakgBsAtoQhk +xls/y3Z113I11mhiUc1ewCf1Oq4anJgINdhLhQoextfedmYrenfcvdzaFQnYAE08XhONTWEK8+js +Fpo1oqAKoAA8CWjoJJTHM8kJ5jsiOiszAKD1+IV/hmW76rosbfnlh1Pp3Mah2srCnXQE9YXiel/c +p5r7uVj2CwxPTuFjjmdLbteNwmrLwsYe3TjsD8cmjKV43ycy+3o76D4llFuXmuCoZEPczXVOSsLv +f5lgGpNZLxJL2jnvMar0/wAOp6jHDH/uO4RViY9f/KpRdfC6k3R9fRyj+pRZVkWKqF10e+hCKaFq +XlH/ALlmhK7Met/uUGZ5ow8XL57lU8/Yt4lx4jUOJphLobTe/wDaHeZLxHXtJEya9o5lFzCqpmPY +CUYoPtDfc9TLj0G5jZvHaMFirAs++oEHq9U4rbNiMp8a6wO/1Zbzn2alC+Nx8P1JfdeBboA+AILx +rin8pfbA1ynvKuFUXZOXXkLbzOp2R56andL2G45MmO0RPWWLEe8GzaffoKb/ADI44Pt9ZXxAuuFa +axtgp0BOSPCcviNX8n3Aw8KTNHB4FiY9StkobLWHVSeghq8M4bkAhKKyV6Hl8RV8MwMZG1Uuz3Jn +IcUQJlMFGlJ6D4hfpymy7iChHKqvVtefxO7Ai1txLBIn7pcojN3jGVhQO0ZgCNfM5ZHycTLycSkr +yhtqD4Bmrfw5cuqsm6xHXyp1seRLcHCp4dQy1bOzslj1MzeJ5dVFnuMVdgOiHxOWzrmyMg2Nrbde +k3vR2OTddcd6A5R8GdZqOo67k4wXrLAQPMRKnzImMZEzm+P1nFz6cxQeVujagWR6jsYiqivlH/Ux +1M+7jWY30i7QHx1gF11tjGyxiSfmVc+503pPidVROHYNNY21b/adVZZySo3uOo1qIZQYd9RCzfYm +TUk/qW71LjGkTA+IYiZmM1T9N9j8Gee5+McXJem0/Wp8GUK6KOi7b5MgzFjsxpJHZGDKSCOxE3cD +OvsxbbLc9lsT7Vc73KX4ln3q1ZyVrPx2J/uAjLyan37z7B+Zp4vqPJqKi0K4EvzvUt1qBMdfb+T5 +gycfzkXXuc35InfE6nO8Y9SjFc1Yqh2Hdj2mH/xFxR26XgD/AMRJf45mWMqW5bBD3KqAZlZtb++7 +kEqTsHe//sG1CcTBvy7OWpD+Sewhz8CyKCTYAQPiGV0LVWPdxqQNADQ6zL4nWq2gopU6+ofmA8x3 +1MlvfeIGbnBeCHitRt94IFbRGus2U9H08v13sT+BNHjeX/D4bY4OmP0rPPbHLMWJ2Yy2EDQjVsos +BdeYDx8wo5L5KpSdLWPAE1+G8NrFtBKgOAXPTf6mzViql5ZBoE87eJZkKbOQ8m+Yjf5EBzcO621y +GCqD0H41Obzq7U6vzM577HTXgzPPeOIvM1eB59nD8xXVj7bHTr8iej1MtlauvUMNgzi/V2ctliYy +HYTq37nMExpZXRZYpZVJUdzNjg+FXYwZgdhv6nVVUJU/uH7iNf1CARrtF0IB113M7jTNVjFl2xJA +5ROey88OrVOugOy67TDs+89NRKdSYILdRC8ZQVJ+PHyJs4fqe3EoFPLzBexPxOdusa2xndiWY7JM +qMUNrzOTAfHC9XO9/E3vT9blVJB0o2Zu3MAoYrsL13Ii0Muw3XvJG9KkDOeqjf6gWcw5A33XN9nX +tOeyMRFWy3Jch+bX7mXmCsW/5RBXUoHaOIRi2asAJ0IRbjqzll3o/EAaRiltDojgv2E1aePmhEWq +rsNHZ7wir1K/8Y1vUCSCAd+IXiZ9b1gLYvN07trXTUD4rxN2TkUgEts8p2NDtD0t5MVGchr2Xe99 +hMPNvD1LX5J2TuZhGyYwBijjfiHU5bJXrnYfqBRtRtSbIBWG3+xI6HiLUWz8xA9RuaVNrMAPfB5x +r6v9MLr4S1il7LaxyjY69Jl5eG+Kyhiv1jYIMGYMO8etGscKoJJ8Cbp4bVg4ivaq22t3G/tmRYo5 +zyjQ+JRFFET01GB0Yid9YiYh1l9KgEHqT8Tco/hewA/NzgdQdwTNGNTY3uU2crL9HN00ZlovNzfV +oCanBrBRk1rpCHPUkQjjYoW4GtwAw30MDpuxvbAvpJceR5mXFFEY0W4o4mpg0XNXutQxPUHxLb8q +7mRDyszLr6esz8u++9wL2LcvQb8RXCkhBV3A6mR5rEVSrdFPT8SBLMdsdmWe6P8AUAx+TB4oooxi +i1Jmt0+5dfuOLbANB2H6MjzNzc2zv5ji1g2+5/MYnbb+Yh+T0kubUY940UUbUWtRpJN8w1CfebkK +WfUu+/mDOAGOjsRo0UkIo+pPl6Rckl7ehuR1INGAj9u0kW2nXvK45YlQp1odukaICSAjgSQWf//Z +""" + +# A config file that tries to override some standard vars: +config_override = """ +[global] +key0 = var0 +home = /home/sweet/home +key1 = var1 +site_packages = planet +key2 = var2 +key3 = var3 +""" + +# A config file that test the automatic type conversion +config_good = """ +[global] +yes = TRUE +no = False +number = 42 +""" + + class test_Env(ClassChecker): """ Test the `ipalib.config.Env` class. @@ -124,6 +186,113 @@ class test_Env(ClassChecker): Test the `ipalib.config.Env.__init__` method. """ o = self.cls() + ipalib = path.dirname(path.abspath(config.__file__)) + assert o.ipalib == ipalib + assert o.site_packages == path.dirname(ipalib) + assert o.script == path.abspath(sys.argv[0]) + assert o.bin == path.dirname(path.abspath(sys.argv[0])) + assert o.home == os.environ['HOME'] + assert o.dot_ipa == path.join(os.environ['HOME'], '.ipa') + + def bootstrap(self, **overrides): + o = self.cls() + o._bootstrap(**overrides) + return o + + def test_bootstrap(self): + """ + Test the `ipalib.config.Env._bootstrap` method. + """ + dot_ipa = path.join(os.environ['HOME'], '.ipa') + + # Test defaults created by _bootstrap(): + o = self.cls() + assert 'in_tree' not in o + assert 'context' not in o + assert 'conf' not in o + o._bootstrap() + assert o.in_tree is False + assert o.context == 'default' + assert o.conf == '/etc/ipa/default.conf' + + # Test overriding values created by _bootstrap() + o = self.bootstrap(in_tree='true', context='server') + assert o.in_tree is True + assert o.context == 'server' + assert o.conf == path.join(dot_ipa, 'server.conf') + o = self.bootstrap(conf='/my/wacky/whatever.conf') + assert o.in_tree is False + assert o.context == 'default' + assert o.conf == '/my/wacky/whatever.conf' + + # Test various overrides and types conversion + kw = dict( + yes=True, + no=False, + num=42, + msg='Hello, world!', + ) + override = dict( + (k, u' %s ' % v) for (k, v) in kw.items() + ) + o = self.cls() + for key in kw: + assert key not in o + o._bootstrap(**override) + for (key, value) in kw.items(): + assert getattr(o, key) == value + assert o[key] == value + + def test_load_config(self): + """ + Test the `ipalib.config.Env._load_config` method. + """ + tmp = TempDir() + assert callable(tmp.join) + + # Test a config file that doesn't exist + no_exist = tmp.join('no_exist.conf') + assert not path.exists(no_exist) + o = self.cls() + keys = tuple(o) + orig = dict((k, o[k]) for k in o) + assert o._load_config(no_exist) is None + assert tuple(o) == keys + + # Test an empty config file + empty = tmp.touch('empty.conf') + assert path.isfile(empty) + assert o._load_config(empty) is None + assert tuple(o) == keys + + # Test a mal-formed config file: + bad = tmp.join('bad.conf') + open(bad, 'w').write(config_bad) + assert path.isfile(bad) + assert o._load_config(bad) is None + assert tuple(o) == keys + + # Test a valid config file that tries to override + override = tmp.join('override.conf') + open(override, 'w').write(config_override) + assert path.isfile(override) + assert o._load_config(override) == (4, 6) + for (k, v) in orig.items(): + assert o[k] is v + assert list(o) == sorted(keys + ('key0', 'key1', 'key2', 'key3')) + for i in xrange(4): + assert o['key%d' % i] == ('var%d' % i) + keys = tuple(o) + + # Test a valid config file with type conversion + good = tmp.join('good.conf') + open(good, 'w').write(config_good) + assert path.isfile(good) + assert o._load_config(good) == (3, 3) + assert list(o) == sorted(keys + ('yes', 'no', 'number')) + assert o.yes is True + assert o.no is False + assert o.number == 42 def test_lock(self): """ @@ -186,6 +355,16 @@ class test_Env(ClassChecker): e = raises(AttributeError, setvar, o, name, value) assert str(e) == \ 'locked: cannot set Env.%s to %r' % (name, value) + o = self.cls() + setvar(o, 'yes', ' true ') + assert o.yes is True + setvar(o, 'no', ' false ') + assert o.no is False + setvar(o, 'msg', u' Hello, world! ') + assert o.msg == 'Hello, world!' + assert type(o.msg) is str + setvar(o, 'num', ' 42 ') + assert o.num == 42 def test_delattr(self): """ @@ -223,11 +402,11 @@ class test_Env(ClassChecker): Test the `ipalib.config.Env.__iter__` method. """ o = self.cls() - assert list(o) == [] + default_keys = tuple(o) keys = ('one', 'two', 'three', 'four', 'five') for key in keys: o[key] = 'the value' - assert list(o) == sorted(keys) + assert list(o) == sorted(keys + default_keys) def test_set_default_env(): -- cgit From 2a41db33c6d9f6efa826e16d91eba76defe899d2 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 24 Oct 2008 15:35:58 -0600 Subject: Env._bootstrap() now raises StandardError if called more than once --- tests/test_ipalib/test_config.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 39dc7906..67eedd14 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -197,6 +197,8 @@ class test_Env(ClassChecker): def bootstrap(self, **overrides): o = self.cls() o._bootstrap(**overrides) + e = raises(StandardError, o._bootstrap) + assert str(e) == 'Env._bootstrap() already called' return o def test_bootstrap(self): -- cgit From 8ca44bcbfa2aec0c7c84205dc08c81f711a22c5d Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 24 Oct 2008 16:02:26 -0600 Subject: Added tests.util.TempHome class for created a tempdir and setting os.environ['HOME'] to it; updated various unit tests for Env so they are run using a tempdir for home --- tests/test_ipalib/test_config.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 67eedd14..01ff2f01 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -27,7 +27,7 @@ from os import path import sys from tests.util import raises, setitem, delitem, ClassChecker from tests.util import getitem, setitem, delitem -from tests.util import TempDir +from tests.util import TempDir, TempHome from ipalib import config @@ -181,34 +181,42 @@ class test_Env(ClassChecker): _cls = config.Env + def new(self): + """ + Set os.environ['HOME'] to a tempdir. + + Returns tuple with new Env instance and the TempHome instance. + """ + home = TempHome() + return (self.cls(), home) + def test_init(self): """ Test the `ipalib.config.Env.__init__` method. """ - o = self.cls() + (o, home) = self.new() ipalib = path.dirname(path.abspath(config.__file__)) assert o.ipalib == ipalib assert o.site_packages == path.dirname(ipalib) assert o.script == path.abspath(sys.argv[0]) assert o.bin == path.dirname(path.abspath(sys.argv[0])) - assert o.home == os.environ['HOME'] - assert o.dot_ipa == path.join(os.environ['HOME'], '.ipa') + assert o.home == home.path + assert o.dot_ipa == home.join('.ipa') def bootstrap(self, **overrides): - o = self.cls() + (o, home) = self.new() o._bootstrap(**overrides) e = raises(StandardError, o._bootstrap) assert str(e) == 'Env._bootstrap() already called' - return o + return (o, home) def test_bootstrap(self): """ Test the `ipalib.config.Env._bootstrap` method. """ - dot_ipa = path.join(os.environ['HOME'], '.ipa') # Test defaults created by _bootstrap(): - o = self.cls() + (o, home) = self.new() assert 'in_tree' not in o assert 'context' not in o assert 'conf' not in o @@ -218,11 +226,11 @@ class test_Env(ClassChecker): assert o.conf == '/etc/ipa/default.conf' # Test overriding values created by _bootstrap() - o = self.bootstrap(in_tree='true', context='server') + (o, home) = self.bootstrap(in_tree='true', context='server') assert o.in_tree is True assert o.context == 'server' - assert o.conf == path.join(dot_ipa, 'server.conf') - o = self.bootstrap(conf='/my/wacky/whatever.conf') + assert o.conf == home.join('.ipa', 'server.conf') + (o, home) = self.bootstrap(conf='/my/wacky/whatever.conf') assert o.in_tree is False assert o.context == 'default' assert o.conf == '/my/wacky/whatever.conf' @@ -237,7 +245,7 @@ class test_Env(ClassChecker): override = dict( (k, u' %s ' % v) for (k, v) in kw.items() ) - o = self.cls() + (o, home) = self.new() for key in kw: assert key not in o o._bootstrap(**override) -- cgit From ac4efac3944d180cffd0ad9d63f631dc928e1d28 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 24 Oct 2008 20:02:14 -0600 Subject: Finished Env._finalize_core() and corresponding unit tests --- tests/test_ipalib/test_config.py | 124 +++++++++++++++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 10 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 01ff2f01..b4c86319 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -28,7 +28,7 @@ import sys from tests.util import raises, setitem, delitem, ClassChecker from tests.util import getitem, setitem, delitem from tests.util import TempDir, TempHome -from ipalib import config +from ipalib import config, constants def test_Environment(): @@ -157,6 +157,7 @@ WfUu+/mDOAGOjsRo0UkIo+pPl6Rckl7ehuR1INGAj9u0kW2nXvK45YlQp1odukaICSAjgSQWf//Z # A config file that tries to override some standard vars: config_override = """ [global] + key0 = var0 home = /home/sweet/home key1 = var1 @@ -165,9 +166,10 @@ key2 = var2 key3 = var3 """ -# A config file that test the automatic type conversion +# A config file that tests the automatic type conversion config_good = """ [global] + yes = TRUE no = False number = 42 @@ -205,7 +207,9 @@ class test_Env(ClassChecker): def bootstrap(self, **overrides): (o, home) = self.new() + assert o._isdone('_bootstrap') is False o._bootstrap(**overrides) + assert o._isdone('_bootstrap') is True e = raises(StandardError, o._bootstrap) assert str(e) == 'Env._bootstrap() already called' return (o, home) @@ -214,7 +218,6 @@ class test_Env(ClassChecker): """ Test the `ipalib.config.Env._bootstrap` method. """ - # Test defaults created by _bootstrap(): (o, home) = self.new() assert 'in_tree' not in o @@ -253,9 +256,110 @@ class test_Env(ClassChecker): assert getattr(o, key) == value assert o[key] == value - def test_load_config(self): + def finalize_core(self, **defaults): + (o, home) = self.new() + assert o._isdone('_finalize_core') is False + o._finalize_core(**defaults) + assert o._isdone('_finalize_core') is True + e = raises(StandardError, o._finalize_core) + assert str(e) == 'Env._finalize_core() already called' + return (o, home) + + def test_finalize_core(self): + """ + Test the `ipalib.config.Env._finalize_core` method. + """ + # Check that calls cascade up the chain: + (o, home) = self.new() + assert o._isdone('_bootstrap') is False + assert o._isdone('_finalize_core') is False + assert o._isdone('_finalize') is False + o._finalize_core() + assert o._isdone('_bootstrap') is True + assert o._isdone('_finalize_core') is True + assert o._isdone('_finalize') is False + + # Check that it can't be called twice: + e = raises(StandardError, o._finalize_core) + assert str(e) == 'Env._finalize_core() already called' + + # Check that _bootstrap() did its job: + (o, home) = self.bootstrap() + assert 'in_tree' in o + assert 'conf' in o + assert 'context' in o + + # Check that keys _finalize_core() will set are not set yet: + assert 'log' not in o + assert 'in_server' not in o + + # Check that _finalize_core() did its job: + o._finalize_core() + assert 'in_server' in o + assert 'log' in o + assert o.in_tree is False + assert o.context == 'default' + assert o.in_server is False + assert o.log == '/var/log/ipa/default.log' + + # Check log is in ~/.ipa/log when context='cli' + (o, home) = self.bootstrap(context='cli') + o._finalize_core() + assert o.in_tree is False + assert o.log == home.join('.ipa', 'log', 'cli.log') + + # Check **defaults can't set in_server nor log: + (o, home) = self.bootstrap(in_server='tRUE') + o._finalize_core(in_server=False) + assert o.in_server is True + (o, home) = self.bootstrap(log='/some/silly/log') + o._finalize_core(log='/a/different/log') + assert o.log == '/some/silly/log' + + # Test loading config file, plus test some in-tree stuff + (o, home) = self.bootstrap(in_tree=True, context='server') + for key in ('yes', 'no', 'number'): + assert key not in o + home.write(config_good, '.ipa', 'server.conf') + o._finalize_core() + assert o.in_tree is True + assert o.context == 'server' + assert o.in_server is True + assert o.log == home.join('.ipa', 'log', 'server.log') + assert o.yes is True + assert o.no is False + assert o.number == 42 + + # Test using DEFAULT_CONFIG: + defaults = dict(constants.DEFAULT_CONFIG) + (o, home) = self.finalize_core(**defaults) + assert list(o) == sorted(defaults) + for (key, value) in defaults.items(): + if value is None: + continue + assert o[key] is value + + def test_finalize(self): + """ + Test the `ipalib.config.Env._finalize` method. + """ + # Check that calls cascade up the chain: + (o, home) = self.new() + assert o._isdone('_bootstrap') is False + assert o._isdone('_finalize_core') is False + assert o._isdone('_finalize') is False + o._finalize() + assert o._isdone('_bootstrap') is True + assert o._isdone('_finalize_core') is True + assert o._isdone('_finalize') is True + + # Check that it can't be called twice: + e = raises(StandardError, o._finalize) + assert str(e) == 'Env._finalize() already called' + + def test_merge_config(self): """ - Test the `ipalib.config.Env._load_config` method. + Test the `ipalib.config.Env._merge_config` method. """ tmp = TempDir() assert callable(tmp.join) @@ -266,27 +370,27 @@ class test_Env(ClassChecker): o = self.cls() keys = tuple(o) orig = dict((k, o[k]) for k in o) - assert o._load_config(no_exist) is None + assert o._merge_config(no_exist) is None assert tuple(o) == keys # Test an empty config file empty = tmp.touch('empty.conf') assert path.isfile(empty) - assert o._load_config(empty) is None + assert o._merge_config(empty) is None assert tuple(o) == keys # Test a mal-formed config file: bad = tmp.join('bad.conf') open(bad, 'w').write(config_bad) assert path.isfile(bad) - assert o._load_config(bad) is None + assert o._merge_config(bad) is None assert tuple(o) == keys # Test a valid config file that tries to override override = tmp.join('override.conf') open(override, 'w').write(config_override) assert path.isfile(override) - assert o._load_config(override) == (4, 6) + assert o._merge_config(override) == (4, 6) for (k, v) in orig.items(): assert o[k] is v assert list(o) == sorted(keys + ('key0', 'key1', 'key2', 'key3')) @@ -298,7 +402,7 @@ class test_Env(ClassChecker): good = tmp.join('good.conf') open(good, 'w').write(config_good) assert path.isfile(good) - assert o._load_config(good) == (3, 3) + assert o._merge_config(good) == (3, 3) assert list(o) == sorted(keys + ('yes', 'no', 'number')) assert o.yes is True assert o.no is False -- cgit From 759734864e72c209d62c970d2e325e96ae02fcb7 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 24 Oct 2008 20:21:27 -0600 Subject: Finished Env._finalize() and corresponding unit tests --- tests/test_ipalib/test_config.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index b4c86319..6136bdf0 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -170,8 +170,8 @@ key3 = var3 config_good = """ [global] -yes = TRUE -no = False +yes = tRUE +no = fALse number = 42 """ @@ -357,6 +357,25 @@ class test_Env(ClassChecker): e = raises(StandardError, o._finalize) assert str(e) == 'Env._finalize() already called' + # Check that _finalize() calls __lock__() + (o, home) = self.new() + assert o.__islocked__() is False + o._finalize() + assert o.__islocked__() is True + e = raises(StandardError, o.__lock__) + assert str(e) == 'Env.__lock__() already called' + + # Check that **lastchance works + (o, home) = self.finalize_core() + key = 'just_one_more_key' + value = 'with one more value' + lastchance = {key: value} + assert key not in o + assert o._isdone('_finalize') is False + o._finalize(**lastchance) + assert key in o + assert o[key] is value + def test_merge_config(self): """ Test the `ipalib.config.Env._merge_config` method. -- cgit From 6b8abb0d78a8d86d7ca52083a267fe226bf74656 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 26 Oct 2008 23:28:06 -0600 Subject: Implemented placeholder API.bootstrap() method; added API __doing(), __do_if_not_done(), isdone() methods borrowed from Env; API.finalize() now cascades call to API.bootstrap() --- tests/test_ipalib/test_plugable.py | 187 +++++++++++++++++++++---------------- 1 file changed, 105 insertions(+), 82 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 61011797..bdbadae5 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -764,99 +764,122 @@ def test_Registrar(): assert issubclass(klass, base) -def test_API(): +class test_API(ClassChecker): """ Test the `ipalib.plugable.API` class. """ - assert issubclass(plugable.API, plugable.ReadOnly) - # Setup the test bases, create the API: - class base0(plugable.Plugin): - __public__ = frozenset(( - 'method', - )) + _cls = plugable.API - def method(self, n): - return n + def test_API(self): + """ + Test the `ipalib.plugable.API` class. + """ + assert issubclass(plugable.API, plugable.ReadOnly) - class base1(plugable.Plugin): - __public__ = frozenset(( - 'method', - )) + # Setup the test bases, create the API: + class base0(plugable.Plugin): + __public__ = frozenset(( + 'method', + )) - def method(self, n): - return n + 1 + def method(self, n): + return n - api = plugable.API(base0, base1) - r = api.register - assert isinstance(r, plugable.Registrar) - assert read_only(api, 'register') is r + class base1(plugable.Plugin): + __public__ = frozenset(( + 'method', + )) - class base0_plugin0(base0): - pass - r(base0_plugin0) + def method(self, n): + return n + 1 - class base0_plugin1(base0): - pass - r(base0_plugin1) + api = plugable.API(base0, base1) + r = api.register + assert isinstance(r, plugable.Registrar) + assert read_only(api, 'register') is r - class base0_plugin2(base0): - pass - r(base0_plugin2) + class base0_plugin0(base0): + pass + r(base0_plugin0) - class base1_plugin0(base1): - pass - r(base1_plugin0) + class base0_plugin1(base0): + pass + r(base0_plugin1) - class base1_plugin1(base1): - pass - r(base1_plugin1) + class base0_plugin2(base0): + pass + r(base0_plugin2) - class base1_plugin2(base1): - pass - r(base1_plugin2) - - # Test API instance: - api.finalize() - - def get_base(b): - return 'base%d' % b - - def get_plugin(b, p): - return 'base%d_plugin%d' % (b, p) - - for b in xrange(2): - base_name = get_base(b) - ns = getattr(api, base_name) - assert isinstance(ns, plugable.NameSpace) - assert read_only(api, base_name) is ns - assert len(ns) == 3 - for p in xrange(3): - plugin_name = get_plugin(b, p) - proxy = ns[plugin_name] - assert isinstance(proxy, plugable.PluginProxy) - assert proxy.name == plugin_name - assert read_only(ns, plugin_name) is proxy - assert read_only(proxy, 'method')(7) == 7 + b - - # Test that calling finilize again raises AssertionError: - raises(AssertionError, api.finalize) - - # Test with base class that doesn't request a proxy - class NoProxy(plugable.Plugin): - __proxy__ = False - api = plugable.API(NoProxy) - class plugin0(NoProxy): - pass - api.register(plugin0) - class plugin1(NoProxy): - pass - api.register(plugin1) - api.finalize() - names = ['plugin0', 'plugin1'] - assert list(api.NoProxy) == names - for name in names: - plugin = api.NoProxy[name] - assert getattr(api.NoProxy, name) is plugin - assert isinstance(plugin, plugable.Plugin) - assert not isinstance(plugin, plugable.PluginProxy) + class base1_plugin0(base1): + pass + r(base1_plugin0) + + class base1_plugin1(base1): + pass + r(base1_plugin1) + + class base1_plugin2(base1): + pass + r(base1_plugin2) + + # Test API instance: + assert api.isdone('bootstrap') is False + assert api.isdone('finalize') is False + api.finalize() + assert api.isdone('bootstrap') is True + assert api.isdone('finalize') is True + + def get_base(b): + return 'base%d' % b + + def get_plugin(b, p): + return 'base%d_plugin%d' % (b, p) + + for b in xrange(2): + base_name = get_base(b) + ns = getattr(api, base_name) + assert isinstance(ns, plugable.NameSpace) + assert read_only(api, base_name) is ns + assert len(ns) == 3 + for p in xrange(3): + plugin_name = get_plugin(b, p) + proxy = ns[plugin_name] + assert isinstance(proxy, plugable.PluginProxy) + assert proxy.name == plugin_name + assert read_only(ns, plugin_name) is proxy + assert read_only(proxy, 'method')(7) == 7 + b + + # Test that calling finilize again raises AssertionError: + e = raises(StandardError, api.finalize) + assert str(e) == 'API.finalize() already called', str(e) + + # Test with base class that doesn't request a proxy + class NoProxy(plugable.Plugin): + __proxy__ = False + api = plugable.API(NoProxy) + class plugin0(NoProxy): + pass + api.register(plugin0) + class plugin1(NoProxy): + pass + api.register(plugin1) + api.finalize() + names = ['plugin0', 'plugin1'] + assert list(api.NoProxy) == names + for name in names: + plugin = api.NoProxy[name] + assert getattr(api.NoProxy, name) is plugin + assert isinstance(plugin, plugable.Plugin) + assert not isinstance(plugin, plugable.PluginProxy) + + def test_bootstrap(self): + """ + Test the `ipalib.plugable.API.bootstrap` method. + """ + o = self.cls() + assert o.isdone('bootstrap') is False + o.bootstrap() + assert o.isdone('bootstrap') is True + e = raises(StandardError, o.bootstrap) + assert str(e) == 'API.bootstrap() already called' -- cgit From 4fe03f5e17dfe9d4478a75dfada2282535c989fe Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 26 Oct 2008 23:53:44 -0600 Subject: Added API.load_plugins() place-holder, which cascades call to API.bootstrap() --- tests/test_ipalib/test_plugable.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index bdbadae5..ba98e752 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -883,3 +883,16 @@ class test_API(ClassChecker): assert o.isdone('bootstrap') is True e = raises(StandardError, o.bootstrap) assert str(e) == 'API.bootstrap() already called' + + def test_load_plugins(self): + """ + Test the `ipalib.plugable.API.load_plugins` method. + """ + o = self.cls() + assert o.isdone('bootstrap') is False + assert o.isdone('load_plugins') is False + o.load_plugins(dry_run=True) + assert o.isdone('bootstrap') is True + assert o.isdone('load_plugins') is True + e = raises(StandardError, o.load_plugins) + assert str(e) == 'API.load_plugins() already called' -- cgit From 28dd8e74bdefd62307881f6e086af59db97a21a0 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 00:58:25 -0600 Subject: Env._bootstrap() now also sets Env.conf_default --- tests/test_ipalib/test_config.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 6136bdf0..0608bf8e 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -227,6 +227,7 @@ class test_Env(ClassChecker): assert o.in_tree is False assert o.context == 'default' assert o.conf == '/etc/ipa/default.conf' + assert o.conf_default == o.conf # Test overriding values created by _bootstrap() (o, home) = self.bootstrap(in_tree='true', context='server') @@ -237,6 +238,12 @@ class test_Env(ClassChecker): assert o.in_tree is False assert o.context == 'default' assert o.conf == '/my/wacky/whatever.conf' + assert o.conf_default == '/etc/ipa/default.conf' + (o, home) = self.bootstrap(conf_default='/my/wacky/default.conf') + assert o.in_tree is False + assert o.context == 'default' + assert o.conf == '/etc/ipa/default.conf' + assert o.conf_default == '/my/wacky/default.conf' # Test various overrides and types conversion kw = dict( -- cgit From 25a7df9615058372b81a41df6baa2c4692df0063 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 01:09:53 -0600 Subject: Env._finalize_core() now also loads config from Env.conf_default --- tests/test_ipalib/test_config.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 0608bf8e..ddfbb708 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -175,6 +175,14 @@ no = fALse number = 42 """ +# A default config file to make sure it does not overwrite the explicit one +config_default = """ +[global] + +yes = Hello +not_in_other = foo_bar +""" + class test_Env(ClassChecker): """ @@ -328,6 +336,7 @@ class test_Env(ClassChecker): for key in ('yes', 'no', 'number'): assert key not in o home.write(config_good, '.ipa', 'server.conf') + home.write(config_default, '.ipa', 'default.conf') o._finalize_core() assert o.in_tree is True assert o.context == 'server' @@ -336,6 +345,7 @@ class test_Env(ClassChecker): assert o.yes is True assert o.no is False assert o.number == 42 + assert o.not_in_other == 'foo_bar' # Test using DEFAULT_CONFIG: defaults = dict(constants.DEFAULT_CONFIG) -- cgit From d76202fea37e63fbc660ed2cf2059f455b8e2213 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 01:35:40 -0600 Subject: API.env is now an Env instance rather than an Environment instance --- tests/test_ipalib/test_crud.py | 2 +- tests/test_ipalib/test_frontend.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index 794921aa..421eaca8 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -40,7 +40,7 @@ class CrudChecker(ClassChecker): frontend.Method, frontend.Property, ) - config.set_default_env(api.env) + #config.set_default_env(api.env) class user(frontend.Object): takes_params = ( 'givenname', diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 966b5e93..5a678b5b 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -764,7 +764,8 @@ class test_Command(ClassChecker): # Test in server context: api = plugable.API(self.cls) - api.env.update(dict(server_context=True)) + #api.env.update(dict(server_context=True)) + api.env.in_server = True api.finalize() o = my_cmd() o.set_api(api) @@ -774,7 +775,8 @@ class test_Command(ClassChecker): # Test in non-server context api = plugable.API(self.cls) - api.env.update(dict(server_context=False)) + #api.env.update(dict(server_context=False)) + api.env.in_server = False api.finalize() o = my_cmd() o.set_api(api) @@ -907,7 +909,7 @@ class test_Object(ClassChecker): frontend.Method, frontend.Property, ) - config.set_default_env(api.env) + #config.set_default_env(api.env) api.finalize() # Test with no primary keys: @@ -964,7 +966,7 @@ class test_Object(ClassChecker): frontend.Property, backend.Backend, ) - config.set_default_env(api.env) + #config.set_default_env(api.env) class ldap(backend.Backend): whatever = 'It worked!' api.register(ldap) -- cgit From 10026284dbf8f1b8a6eedf3b1c6ce05da568b4fa Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 14:48:02 -0600 Subject: Started cleanup work on CLI class, added unit tests for CLI.parse_globals() --- tests/test_ipalib/test_cli.py | 105 +++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 52 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 50bfb932..10f23989 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -22,7 +22,7 @@ Test the `ipalib.cli` module. """ from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker -from ipalib import cli, plugable +from ipalib import cli, plugable, frontend, backend def test_to_cli(): @@ -81,60 +81,61 @@ class test_CLI(ClassChecker): """ _cls = cli.CLI - def test_class(self): - """ - Test the `ipalib.cli.CLI` class. - """ - assert type(self.cls.api) is property - - def test_api(self): - """ - Test the `ipalib.cli.CLI.api` property. - """ - api = 'the plugable.API instance' - o = self.cls(api) - assert read_only(o, 'api') is api - - def dont_parse(self): - """ - Test the `ipalib.cli.CLI.parse` method. - """ - o = self.cls(None) - args = ['hello', 'naughty', 'nurse'] - kw = dict( - first_name='Naughty', - last_name='Nurse', + def new(self, argv): + api = plugable.API( + frontend.Command, + frontend.Object, + frontend.Method, + frontend.Property, + frontend.Application, + backend.Backend, ) - opts = ['--%s=%s' % (k.replace('_', '-'), v) for (k, v) in kw.items()] - assert o.parse(args + []) == (args, {}) - assert o.parse(opts + []) == ([], kw) - assert o.parse(args + opts) == (args, kw) - assert o.parse(opts + args) == (args, kw) + o = self.cls(api, argv) + assert o.api is api + return o - def test_mcl(self): + def test_init(self): """ - Test the `ipalib.cli.CLI.mcl` property . + Test the `ipalib.cli.CLI.__init__` method. """ - cnt = 100 - api = DummyAPI(cnt) - len(api.Command) == cnt - o = self.cls(api) - assert o.mcl is None - o.build_map() - assert o.mcl == 6 # len('cmd_99') - - def test_dict(self): + argv = ['-v', 'user-add', '--first=Jonh', '--last=Doe'] + o = self.new(argv) + assert type(o.api) is plugable.API + assert o.argv == tuple(argv) + + def test_parse_globals(self): """ - Test container emulation of `ipalib.cli.CLI` class. + Test the `ipalib.cli.CLI.parse_globals` method. """ - cnt = 25 - api = DummyAPI(cnt) - assert len(api.Command) == cnt - o = self.cls(api) - o.build_map() - for cmd in api.Command(): - key = cli.to_cli(cmd.name) - assert key in o - assert o[key] is cmd - assert cmd.name not in o - raises(KeyError, getitem, o, cmd.name) + # Test with empty argv + o = self.new([]) + assert not hasattr(o, 'options') + assert not hasattr(o, 'cmd_argv') + assert o.isdone('parse_globals') is False + o.parse_globals() + assert o.isdone('parse_globals') is True + assert o.options.interactive is True + assert o.options.verbose is False + assert o.options.config_file is None + assert o.options.environment is None + assert o.cmd_argv == tuple() + e = raises(StandardError, o.parse_globals) + assert str(e) == 'CLI.parse_globals() already called' + + # Test with a populated argv + argv = ('-a', '-n', '-v', '-c', '/my/config.conf', '-e', 'my_key=my_val') + cmd_argv = ('user-add', '--first', 'John', '--last', 'Doe') + o = self.new(argv + cmd_argv) + assert not hasattr(o, 'options') + assert not hasattr(o, 'cmd_argv') + assert o.isdone('parse_globals') is False + o.parse_globals() + assert o.isdone('parse_globals') is True + assert o.options.prompt_all is True + assert o.options.interactive is False + assert o.options.verbose is True + assert o.options.config_file == '/my/config.conf' + assert o.options.environment == 'my_key=my_val' + assert o.cmd_argv == cmd_argv + e = raises(StandardError, o.parse_globals) + assert str(e) == 'CLI.parse_globals() already called' -- cgit From 17fd9cc4315f171a8d9e9d189936eea8ba2af0c0 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 14:49:34 -0600 Subject: Started cleanup work on CLI class, added unit tests for CLI.parse_globals() --- tests/test_ipalib/test_cli.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 10f23989..28e441e7 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -139,3 +139,8 @@ class test_CLI(ClassChecker): assert o.cmd_argv == cmd_argv e = raises(StandardError, o.parse_globals) assert str(e) == 'CLI.parse_globals() already called' + + def test_bootstrap(self): + """ + Test the `ipalib.cli.CLI.bootstrap` method. + """ -- cgit From e6254026fe73c423d357a2fa1489de35475da46c Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 15:19:49 -0600 Subject: Implemented basic CLI.bootstrap(); added corresponding unit tests --- tests/test_ipalib/test_cli.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 28e441e7..293371b7 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -22,6 +22,7 @@ Test the `ipalib.cli` module. """ from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker +from tests.util import TempHome from ipalib import cli, plugable, frontend, backend @@ -81,7 +82,8 @@ class test_CLI(ClassChecker): """ _cls = cli.CLI - def new(self, argv): + def new(self, argv=tuple()): + home = TempHome() api = plugable.API( frontend.Command, frontend.Object, @@ -90,17 +92,18 @@ class test_CLI(ClassChecker): frontend.Application, backend.Backend, ) + api.env.in_tree = True o = self.cls(api, argv) assert o.api is api - return o + return (o, api, home) def test_init(self): """ Test the `ipalib.cli.CLI.__init__` method. """ argv = ['-v', 'user-add', '--first=Jonh', '--last=Doe'] - o = self.new(argv) - assert type(o.api) is plugable.API + (o, api, home) = self.new(argv) + assert o.api is api assert o.argv == tuple(argv) def test_parse_globals(self): @@ -108,7 +111,7 @@ class test_CLI(ClassChecker): Test the `ipalib.cli.CLI.parse_globals` method. """ # Test with empty argv - o = self.new([]) + (o, api, home) = self.new() assert not hasattr(o, 'options') assert not hasattr(o, 'cmd_argv') assert o.isdone('parse_globals') is False @@ -125,7 +128,7 @@ class test_CLI(ClassChecker): # Test with a populated argv argv = ('-a', '-n', '-v', '-c', '/my/config.conf', '-e', 'my_key=my_val') cmd_argv = ('user-add', '--first', 'John', '--last', 'Doe') - o = self.new(argv + cmd_argv) + (o, api, home) = self.new(argv + cmd_argv) assert not hasattr(o, 'options') assert not hasattr(o, 'cmd_argv') assert o.isdone('parse_globals') is False @@ -144,3 +147,14 @@ class test_CLI(ClassChecker): """ Test the `ipalib.cli.CLI.bootstrap` method. """ + (o, api, home) = self.new() + keys = tuple(api.env) + assert o.isdone('parse_globals') is False + assert o.isdone('bootstrap') is False + o.bootstrap() + assert o.isdone('parse_globals') is True + assert o.isdone('bootstrap') is True + e = raises(StandardError, o.bootstrap) + assert str(e) == 'CLI.bootstrap() already called' + assert api.env.verbose is False + assert api.env.context == 'cli' -- cgit From bb9691099b7b025fc491279314d8803f4fa3b571 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 15:36:41 -0600 Subject: API.bootstrap() now calls Env._finalize_core(); updated unit tests --- tests/test_ipalib/test_cli.py | 2 ++ tests/test_ipalib/test_plugable.py | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 293371b7..39959270 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -149,9 +149,11 @@ class test_CLI(ClassChecker): """ (o, api, home) = self.new() keys = tuple(api.env) + assert api.isdone('bootstrap') is False assert o.isdone('parse_globals') is False assert o.isdone('bootstrap') is False o.bootstrap() + assert api.isdone('bootstrap') is True assert o.isdone('parse_globals') is True assert o.isdone('bootstrap') is True e = raises(StandardError, o.bootstrap) diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index ba98e752..50cab930 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -23,7 +23,7 @@ Test the `ipalib.plugable` module. from tests.util import raises, no_set, no_del, read_only from tests.util import getitem, setitem, delitem -from tests.util import ClassChecker +from tests.util import ClassChecker, TempHome from ipalib import plugable, errors @@ -771,6 +771,12 @@ class test_API(ClassChecker): _cls = plugable.API + def new(self, *bases): + home = TempHome() + api = self.cls(*bases) + api.env.in_tree = True + return (api, home) + def test_API(self): """ Test the `ipalib.plugable.API` class. @@ -877,10 +883,14 @@ class test_API(ClassChecker): """ Test the `ipalib.plugable.API.bootstrap` method. """ - o = self.cls() + (o, home) = self.new() + assert o.env._isdone('_bootstrap') is False + assert o.env._isdone('_finalize_core') is False assert o.isdone('bootstrap') is False o.bootstrap() assert o.isdone('bootstrap') is True + assert o.env._isdone('_bootstrap') is True + assert o.env._isdone('_finalize_core') is True e = raises(StandardError, o.bootstrap) assert str(e) == 'API.bootstrap() already called' -- cgit From 491e295412fceead7cf0c6c9cdd44904541e4044 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 16:08:17 -0600 Subject: Unit test for CLI.boostrap() now checks that -e overrides and values from config files are merged in correctly --- tests/test_ipalib/test_cli.py | 41 ++++++++++++++++++++++++++++++++++++++ tests/test_ipalib/test_plugable.py | 3 ++- 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 39959270..389bb52c 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -76,6 +76,24 @@ class DummyAPI(object): pass +config_cli = """ +[global] + +from_cli_conf = set in cli.conf +""" + +config_default = """ +[global] + +from_default_conf = set in default.conf + +# Make sure cli.conf is loaded first: +from_cli_conf = overridden in default.conf +""" + + + + class test_CLI(ClassChecker): """ Test the `ipalib.cli.CLI` class. @@ -147,6 +165,7 @@ class test_CLI(ClassChecker): """ Test the `ipalib.cli.CLI.bootstrap` method. """ + # Test with empty argv (o, api, home) = self.new() keys = tuple(api.env) assert api.isdone('bootstrap') is False @@ -160,3 +179,25 @@ class test_CLI(ClassChecker): assert str(e) == 'CLI.bootstrap() already called' assert api.env.verbose is False assert api.env.context == 'cli' + keys = tuple(api.env) + added = ( + 'my_key', + 'whatever', + 'from_default_conf', + 'from_cli_conf' + ) + for key in added: + assert key not in api.env + assert key not in keys + + # Test with a populated argv + argv = ['-e', 'my_key=my_val,whatever=Hello'] + (o, api, home) = self.new(argv) + home.write(config_default, '.ipa', 'default.conf') + home.write(config_cli, '.ipa', 'cli.conf') + o.bootstrap() + assert api.env.my_key == 'my_val' + assert api.env.whatever == 'Hello' + assert api.env.from_default_conf == 'set in default.conf' + assert api.env.from_cli_conf == 'set in cli.conf' + assert list(api.env) == sorted(keys + added) diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 50cab930..85b5303c 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -887,10 +887,11 @@ class test_API(ClassChecker): assert o.env._isdone('_bootstrap') is False assert o.env._isdone('_finalize_core') is False assert o.isdone('bootstrap') is False - o.bootstrap() + o.bootstrap(my_test_override='Hello, world!') assert o.isdone('bootstrap') is True assert o.env._isdone('_bootstrap') is True assert o.env._isdone('_finalize_core') is True + assert o.env.my_test_override == 'Hello, world!' e = raises(StandardError, o.bootstrap) assert str(e) == 'API.bootstrap() already called' -- cgit From 9b1e3f59465c6ba33f4266bc3add469b5e1711eb Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 19:21:49 -0600 Subject: More docstrings, functionality, and unit tests for improved CLI class --- tests/test_ipalib/test_cli.py | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 389bb52c..7bcbfb0c 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -115,6 +115,17 @@ class test_CLI(ClassChecker): assert o.api is api return (o, api, home) + def check_cascade(self, *names): + (o, api, home) = self.new() + method = getattr(o, names[0]) + for name in names: + assert o.isdone(name) is False + method() + for name in names: + assert o.isdone(name) is True + e = raises(StandardError, method) + assert str(e) == 'CLI.%s() already called' % names[0] + def test_init(self): """ Test the `ipalib.cli.CLI.__init__` method. @@ -201,3 +212,36 @@ class test_CLI(ClassChecker): assert api.env.from_default_conf == 'set in default.conf' assert api.env.from_cli_conf == 'set in cli.conf' assert list(api.env) == sorted(keys + added) + + def test_load_plugins(self): + """ + Test the `ipalib.cli.CLI.load_plugins` method. + """ + self.check_cascade( + 'load_plugins', + 'bootstrap', + 'parse_globals' + ) + (o, api, home) = self.new() + assert api.isdone('load_plugins') is False + o.load_plugins() + assert api.isdone('load_plugins') is True + + def test_finalize(self): + """ + Test the `ipalib.cli.CLI.finalize` method. + """ + self.check_cascade( + 'finalize', + 'load_plugins', + 'bootstrap', + 'parse_globals' + ) + + (o, api, home) = self.new() + assert api.isdone('finalize') is False + assert 'Command' not in api + o.finalize() + assert api.isdone('finalize') is True + assert list(api.Command) == \ + sorted(k.__name__ for k in cli.cli_application_commands) -- cgit From 6e456cc7494bc00e905361f3e6d42dff99089c6b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 23:30:55 -0600 Subject: More CLI cleanup, got all basics working again --- tests/test_ipalib/test_cli.py | 141 +++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 64 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 7bcbfb0c..c4740875 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -110,6 +110,7 @@ class test_CLI(ClassChecker): frontend.Application, backend.Backend, ) + api.env.mode = 'unit-test' api.env.in_tree = True o = self.cls(api, argv) assert o.api is api @@ -135,57 +136,65 @@ class test_CLI(ClassChecker): assert o.api is api assert o.argv == tuple(argv) - def test_parse_globals(self): + def test_run(self): """ - Test the `ipalib.cli.CLI.parse_globals` method. + Test the `ipalib.cli.CLI.run` method. """ - # Test with empty argv + self.check_cascade( + 'run', + 'finalize', + 'load_plugins', + 'bootstrap', + 'parse_globals' + ) + + def test_finalize(self): + """ + Test the `ipalib.cli.CLI.finalize` method. + """ + self.check_cascade( + 'finalize', + 'load_plugins', + 'bootstrap', + 'parse_globals' + ) + (o, api, home) = self.new() - assert not hasattr(o, 'options') - assert not hasattr(o, 'cmd_argv') - assert o.isdone('parse_globals') is False - o.parse_globals() - assert o.isdone('parse_globals') is True - assert o.options.interactive is True - assert o.options.verbose is False - assert o.options.config_file is None - assert o.options.environment is None - assert o.cmd_argv == tuple() - e = raises(StandardError, o.parse_globals) - assert str(e) == 'CLI.parse_globals() already called' + assert api.isdone('finalize') is False + assert 'Command' not in api + o.finalize() + assert api.isdone('finalize') is True + assert list(api.Command) == \ + sorted(k.__name__ for k in cli.cli_application_commands) - # Test with a populated argv - argv = ('-a', '-n', '-v', '-c', '/my/config.conf', '-e', 'my_key=my_val') - cmd_argv = ('user-add', '--first', 'John', '--last', 'Doe') - (o, api, home) = self.new(argv + cmd_argv) - assert not hasattr(o, 'options') - assert not hasattr(o, 'cmd_argv') - assert o.isdone('parse_globals') is False - o.parse_globals() - assert o.isdone('parse_globals') is True - assert o.options.prompt_all is True - assert o.options.interactive is False - assert o.options.verbose is True - assert o.options.config_file == '/my/config.conf' - assert o.options.environment == 'my_key=my_val' - assert o.cmd_argv == cmd_argv - e = raises(StandardError, o.parse_globals) - assert str(e) == 'CLI.parse_globals() already called' + def test_load_plugins(self): + """ + Test the `ipalib.cli.CLI.load_plugins` method. + """ + self.check_cascade( + 'load_plugins', + 'bootstrap', + 'parse_globals' + ) + (o, api, home) = self.new() + assert api.isdone('load_plugins') is False + o.load_plugins() + assert api.isdone('load_plugins') is True def test_bootstrap(self): """ Test the `ipalib.cli.CLI.bootstrap` method. """ + self.check_cascade( + 'bootstrap', + 'parse_globals' + ) # Test with empty argv (o, api, home) = self.new() keys = tuple(api.env) assert api.isdone('bootstrap') is False - assert o.isdone('parse_globals') is False - assert o.isdone('bootstrap') is False o.bootstrap() assert api.isdone('bootstrap') is True - assert o.isdone('parse_globals') is True - assert o.isdone('bootstrap') is True e = raises(StandardError, o.bootstrap) assert str(e) == 'CLI.bootstrap() already called' assert api.env.verbose is False @@ -213,35 +222,39 @@ class test_CLI(ClassChecker): assert api.env.from_cli_conf == 'set in cli.conf' assert list(api.env) == sorted(keys + added) - def test_load_plugins(self): + def test_parse_globals(self): """ - Test the `ipalib.cli.CLI.load_plugins` method. + Test the `ipalib.cli.CLI.parse_globals` method. """ - self.check_cascade( - 'load_plugins', - 'bootstrap', - 'parse_globals' - ) + # Test with empty argv (o, api, home) = self.new() - assert api.isdone('load_plugins') is False - o.load_plugins() - assert api.isdone('load_plugins') is True - - def test_finalize(self): - """ - Test the `ipalib.cli.CLI.finalize` method. - """ - self.check_cascade( - 'finalize', - 'load_plugins', - 'bootstrap', - 'parse_globals' - ) + assert not hasattr(o, 'options') + assert not hasattr(o, 'cmd_argv') + assert o.isdone('parse_globals') is False + o.parse_globals() + assert o.isdone('parse_globals') is True + assert o.options.interactive is True + assert o.options.verbose is False + assert o.options.config_file is None + assert o.options.environment is None + assert o.cmd_argv == tuple() + e = raises(StandardError, o.parse_globals) + assert str(e) == 'CLI.parse_globals() already called' - (o, api, home) = self.new() - assert api.isdone('finalize') is False - assert 'Command' not in api - o.finalize() - assert api.isdone('finalize') is True - assert list(api.Command) == \ - sorted(k.__name__ for k in cli.cli_application_commands) + # Test with a populated argv + argv = ('-a', '-n', '-v', '-c', '/my/config.conf', '-e', 'my_key=my_val') + cmd_argv = ('user-add', '--first', 'John', '--last', 'Doe') + (o, api, home) = self.new(argv + cmd_argv) + assert not hasattr(o, 'options') + assert not hasattr(o, 'cmd_argv') + assert o.isdone('parse_globals') is False + o.parse_globals() + assert o.isdone('parse_globals') is True + assert o.options.prompt_all is True + assert o.options.interactive is False + assert o.options.verbose is True + assert o.options.config_file == '/my/config.conf' + assert o.options.environment == 'my_key=my_val' + assert o.cmd_argv == cmd_argv + e = raises(StandardError, o.parse_globals) + assert str(e) == 'CLI.parse_globals() already called' -- cgit From 83d6c95e4636049a5bcedb533ad49f6e2cf79dfe Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 23:39:43 -0600 Subject: API.load_plugins() no longer takes dry_run=False kwarg and instead checks in env.mode == 'unit_test' to decide whether to load the plugins; it also only loads ipa_server.plugins in env.in_server is True --- tests/test_ipalib/test_cli.py | 2 +- tests/test_ipalib/test_plugable.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index c4740875..7b3239d7 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -110,7 +110,7 @@ class test_CLI(ClassChecker): frontend.Application, backend.Backend, ) - api.env.mode = 'unit-test' + api.env.mode = 'unit_test' api.env.in_tree = True o = self.cls(api, argv) assert o.api is api diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 85b5303c..c7b8abbd 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -774,6 +774,7 @@ class test_API(ClassChecker): def new(self, *bases): home = TempHome() api = self.cls(*bases) + api.env.mode = 'unit_test' api.env.in_tree = True return (api, home) @@ -899,10 +900,10 @@ class test_API(ClassChecker): """ Test the `ipalib.plugable.API.load_plugins` method. """ - o = self.cls() + (o, home) = self.new() assert o.isdone('bootstrap') is False assert o.isdone('load_plugins') is False - o.load_plugins(dry_run=True) + o.load_plugins() assert o.isdone('bootstrap') is True assert o.isdone('load_plugins') is True e = raises(StandardError, o.load_plugins) -- cgit From ddb5449c7faabbd4c1b71adfe84c386b943a163f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 30 Oct 2008 01:11:33 -0600 Subject: Did some initial work for Context plugins --- tests/test_ipalib/test_backend.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_backend.py b/tests/test_ipalib/test_backend.py index cd490fe0..88bd2da4 100644 --- a/tests/test_ipalib/test_backend.py +++ b/tests/test_ipalib/test_backend.py @@ -22,12 +22,12 @@ Test the `ipalib.backend` module. """ from ipalib import backend, plugable, errors -from tests.util import ClassChecker +from tests.util import ClassChecker, raises class test_Backend(ClassChecker): """ - Test the `backend.Backend` class. + Test the `ipalib.backend.Backend` class. """ _cls = backend.Backend @@ -35,3 +35,21 @@ class test_Backend(ClassChecker): def test_class(self): assert self.cls.__bases__ == (plugable.Plugin,) assert self.cls.__proxy__ is False + + +class test_Context(ClassChecker): + """ + Test the `ipalib.backend.Context` class. + """ + + _cls = backend.Context + + def test_get_value(self): + """ + Test the `ipalib.backend.Context.get_value` method. + """ + class Subclass(self.cls): + pass + o = Subclass() + e = raises(NotImplementedError, o.get_value) + assert str(e) == 'Subclass.get_value()' -- cgit From 2fee6a3e20169f12b837647f0f71d6f28937490f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 30 Oct 2008 01:34:46 -0600 Subject: Added tests.util.get_api() function to create a standard (api, home) tuple for unit testing --- tests/test_ipalib/test_cli.py | 17 ++--------------- tests/test_ipalib/test_plugable.py | 15 +++++---------- 2 files changed, 7 insertions(+), 25 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 7b3239d7..f13db51e 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -21,8 +21,7 @@ Test the `ipalib.cli` module. """ -from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker -from tests.util import TempHome +from tests.util import raises, get_api, ClassChecker from ipalib import cli, plugable, frontend, backend @@ -92,8 +91,6 @@ from_cli_conf = overridden in default.conf """ - - class test_CLI(ClassChecker): """ Test the `ipalib.cli.CLI` class. @@ -101,17 +98,7 @@ class test_CLI(ClassChecker): _cls = cli.CLI def new(self, argv=tuple()): - home = TempHome() - api = plugable.API( - frontend.Command, - frontend.Object, - frontend.Method, - frontend.Property, - frontend.Application, - backend.Backend, - ) - api.env.mode = 'unit_test' - api.env.in_tree = True + (api, home) = get_api() o = self.cls(api, argv) assert o.api is api return (o, api, home) diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index c7b8abbd..ce0c79a9 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -23,7 +23,7 @@ Test the `ipalib.plugable` module. from tests.util import raises, no_set, no_del, read_only from tests.util import getitem, setitem, delitem -from tests.util import ClassChecker, TempHome +from tests.util import ClassChecker, get_api from ipalib import plugable, errors @@ -771,13 +771,6 @@ class test_API(ClassChecker): _cls = plugable.API - def new(self, *bases): - home = TempHome() - api = self.cls(*bases) - api.env.mode = 'unit_test' - api.env.in_tree = True - return (api, home) - def test_API(self): """ Test the `ipalib.plugable.API` class. @@ -802,6 +795,8 @@ class test_API(ClassChecker): return n + 1 api = plugable.API(base0, base1) + api.env.mode = 'unit_test' + api.env.in_tree = True r = api.register assert isinstance(r, plugable.Registrar) assert read_only(api, 'register') is r @@ -884,7 +879,7 @@ class test_API(ClassChecker): """ Test the `ipalib.plugable.API.bootstrap` method. """ - (o, home) = self.new() + (o, home) = get_api() assert o.env._isdone('_bootstrap') is False assert o.env._isdone('_finalize_core') is False assert o.isdone('bootstrap') is False @@ -900,7 +895,7 @@ class test_API(ClassChecker): """ Test the `ipalib.plugable.API.load_plugins` method. """ - (o, home) = self.new() + (o, home) = get_api() assert o.isdone('bootstrap') is False assert o.isdone('load_plugins') is False o.load_plugins() -- cgit From a360b6479c515c723e6b6ad6909f78f40d24a069 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 30 Oct 2008 17:47:56 -0600 Subject: Fixed test_Del.test_get_options() --- tests/test_ipalib/test_crud.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index 421eaca8..259bc60d 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -21,7 +21,7 @@ Test the `ipalib.crud` module. """ -from tests.util import read_only, raises, ClassChecker +from tests.util import read_only, raises, get_api, ClassChecker from ipalib import crud, frontend, plugable, config @@ -35,12 +35,7 @@ class CrudChecker(ClassChecker): Return a finalized `ipalib.plugable.API` instance. """ assert self.cls.__bases__ == (frontend.Method,) - api = plugable.API( - frontend.Object, - frontend.Method, - frontend.Property, - ) - #config.set_default_env(api.env) + (api, home) = get_api() class user(frontend.Object): takes_params = ( 'givenname', @@ -135,8 +130,9 @@ class test_Del(CrudChecker): Test the `ipalib.crud.Del.get_options` method. """ api = self.get_api() - assert list(api.Method.user_verb.options) == [] - assert len(api.Method.user_verb.options) == 0 + assert list(api.Method.user_verb.options) == \ + ['givenname', 'sn', 'initials'] + assert len(api.Method.user_verb.options) == 3 class test_Mod(CrudChecker): -- cgit From a23d41a57f43c3a0f298d3918ae1712181fa544e Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 31 Oct 2008 18:17:08 -0600 Subject: Reoganized global option functionality to it is easy for any script to use the environment-related global options; lite-xmlrpc.py now uses same global options --- tests/test_ipalib/test_cli.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index f13db51e..56545942 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -189,7 +189,6 @@ class test_CLI(ClassChecker): keys = tuple(api.env) added = ( 'my_key', - 'whatever', 'from_default_conf', 'from_cli_conf' ) @@ -203,8 +202,7 @@ class test_CLI(ClassChecker): home.write(config_default, '.ipa', 'default.conf') home.write(config_cli, '.ipa', 'cli.conf') o.bootstrap() - assert api.env.my_key == 'my_val' - assert api.env.whatever == 'Hello' + assert api.env.my_key == 'my_val,whatever=Hello' assert api.env.from_default_conf == 'set in default.conf' assert api.env.from_cli_conf == 'set in cli.conf' assert list(api.env) == sorted(keys + added) @@ -213,22 +211,23 @@ class test_CLI(ClassChecker): """ Test the `ipalib.cli.CLI.parse_globals` method. """ - # Test with empty argv + # Test with empty argv: (o, api, home) = self.new() assert not hasattr(o, 'options') assert not hasattr(o, 'cmd_argv') assert o.isdone('parse_globals') is False o.parse_globals() assert o.isdone('parse_globals') is True + assert o.options.prompt_all is False assert o.options.interactive is True - assert o.options.verbose is False - assert o.options.config_file is None - assert o.options.environment is None + assert o.options.verbose is None + assert o.options.conf is None + assert o.options.env is None assert o.cmd_argv == tuple() e = raises(StandardError, o.parse_globals) assert str(e) == 'CLI.parse_globals() already called' - # Test with a populated argv + # Test with a populated argv: argv = ('-a', '-n', '-v', '-c', '/my/config.conf', '-e', 'my_key=my_val') cmd_argv = ('user-add', '--first', 'John', '--last', 'Doe') (o, api, home) = self.new(argv + cmd_argv) @@ -240,8 +239,14 @@ class test_CLI(ClassChecker): assert o.options.prompt_all is True assert o.options.interactive is False assert o.options.verbose is True - assert o.options.config_file == '/my/config.conf' - assert o.options.environment == 'my_key=my_val' + assert o.options.conf == '/my/config.conf' + assert o.options.env == ['my_key=my_val'] assert o.cmd_argv == cmd_argv e = raises(StandardError, o.parse_globals) assert str(e) == 'CLI.parse_globals() already called' + + # Test with multiple -e args: + argv = ('-e', 'key1=val1', '-e', 'key2=val2') + (o, api, home) = self.new(argv) + o.parse_globals() + assert o.options.env == ['key1=val1', 'key2=val2'] -- cgit From f18c84444d4ed87d79f3cb41156c6b66f49ccac3 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 31 Oct 2008 17:02:51 -0400 Subject: Partially revert back change. Del shouldn't provide default options. It can provide custom ones though, if defined with takes_params() in the class. --- tests/test_ipalib/test_crud.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_crud.py b/tests/test_ipalib/test_crud.py index 259bc60d..ad391e2e 100644 --- a/tests/test_ipalib/test_crud.py +++ b/tests/test_ipalib/test_crud.py @@ -130,9 +130,8 @@ class test_Del(CrudChecker): Test the `ipalib.crud.Del.get_options` method. """ api = self.get_api() - assert list(api.Method.user_verb.options) == \ - ['givenname', 'sn', 'initials'] - assert len(api.Method.user_verb.options) == 3 + assert list(api.Method.user_verb.options) == [] + assert len(api.Method.user_verb.options) == 0 class test_Mod(CrudChecker): -- cgit From 014af24731ff39520a9635694ed99dc9d09669c9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 12 Nov 2008 00:46:04 -0700 Subject: Changed calling signature of output_for_cli(); started work on 'textui' backend plugin --- tests/test_ipalib/test_cli.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 56545942..8cedd088 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -25,6 +25,31 @@ from tests.util import raises, get_api, ClassChecker from ipalib import cli, plugable, frontend, backend +class test_textui(ClassChecker): + _cls = cli.textui + + def test_max_col_width(self): + """ + Test the `ipalib.cli.textui.max_col_width` method. + """ + o = self.cls() + e = raises(TypeError, o.max_col_width, 'hello') + assert str(e) == 'rows: need %r or %r; got %r' % (list, tuple, 'hello') + rows = [ + 'hello', + 'naughty', + 'nurse', + ] + assert o.max_col_width(rows) == len('naughty') + rows = ( + ( 'a', 'bbb', 'ccccc'), + ('aa', 'bbbb', 'cccccc'), + ) + assert o.max_col_width(rows, col=0) == 2 + assert o.max_col_width(rows, col=1) == 4 + assert o.max_col_width(rows, col=2) == 6 + + def test_to_cli(): """ Test the `ipalib.cli.to_cli` function. -- cgit From f04aaff97c9c8c22b36706f2c6d4de6f23d06b95 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 12 Nov 2008 09:55:11 -0700 Subject: output_for_cli signature is now output_for_cli(textui, result, *args, **options) --- tests/test_ipalib/test_frontend.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 5a678b5b..75e098a4 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -735,18 +735,17 @@ class test_Command(ClassChecker): e = raises(errors.ArgumentError, o.args_to_kw, 1, 2, 3) assert str(e) == 'example takes at most 2 arguments' - def test_kw_to_args(self): + def test_params_2_args_options(self): """ - Test the `ipalib.frontend.Command.kw_to_args` method. + Test the `ipalib.frontend.Command.params_2_args_options` method. """ - assert 'kw_to_args' in self.cls.__public__ # Public - o = self.get_instance(args=('one', 'two?')) - assert o.kw_to_args() == (None, None) - assert o.kw_to_args(whatever='hello') == (None, None) - assert o.kw_to_args(one='the one') == ('the one', None) - assert o.kw_to_args(two='the two') == (None, 'the two') - assert o.kw_to_args(whatever='hello', two='Two', one='One') == \ - ('One', 'Two') + assert 'params_2_args_options' in self.cls.__public__ # Public + o = self.get_instance(args=['one'], options=['two']) + assert o.params_2_args_options({}) == ((None,), dict(two=None)) + assert o.params_2_args_options(dict(one=1)) == ((1,), dict(two=None)) + assert o.params_2_args_options(dict(two=2)) == ((None,), dict(two=2)) + assert o.params_2_args_options(dict(two=2, one=1)) == \ + ((1,), dict(two=2)) def test_run(self): """ -- cgit From 8ad5502354a364db606b72455c5514cb56e918ba Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 13 Nov 2008 21:07:47 -0700 Subject: Added util.make_repr() function; added corresponding unit tests --- tests/test_ipalib/test_util.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index 04ff23f0..6729fcda 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -27,7 +27,7 @@ from ipalib import util def test_xmlrpc_marshal(): """ - Test the `util.xmlrpc_marshal` function. + Test the `ipalib.util.xmlrpc_marshal` function. """ f = util.xmlrpc_marshal assert f() == ({},) @@ -39,7 +39,7 @@ def test_xmlrpc_marshal(): def test_xmlrpc_unmarshal(): """ - Test the `util.xmlrpc_unmarshal` function. + Test the `ipalib.util.xmlrpc_unmarshal` function. """ f = util.xmlrpc_unmarshal assert f() == (tuple(), {}) @@ -47,3 +47,15 @@ def test_xmlrpc_unmarshal(): assert f(dict(one=1, two=2)) == (tuple(), dict(one=1, two=2)) assert f(dict(three=3, four=4), 'one', 'two') == \ (('one', 'two'), dict(three=3, four=4)) + + +def test_make_repr(): + """ + Test the `ipalib.util.make_repr` function. + """ + f = util.make_repr + assert f('my') == 'my()' + assert f('my', True, u'hello') == "my(True, u'hello')" + assert f('my', one=1, two='two') == "my(one=1, two='two')" + assert f('my', None, 3, dog='animal', apple='fruit') == \ + "my(None, 3, apple='fruit', dog='animal')" -- cgit From 860d391f3e905e20ba3f409c92d98e68450f3137 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 13 Nov 2008 22:16:04 -0700 Subject: Change Param.__repr__() so it returns the exact expression that could create it; added unit test for Param.__repre__() --- tests/test_ipalib/test_frontend.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 75e098a4..2a8c08fe 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -430,6 +430,18 @@ class test_Param(ClassChecker): 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(): """ -- cgit From f5594dd489317dc406d20f897fc720e0cf89c9d2 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 13 Nov 2008 23:29:35 -0700 Subject: Started work on cleaning up how exceptions are caught and sys.exit() is called in ipalib.cli.CLI --- tests/test_ipalib/test_cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_cli.py b/tests/test_ipalib/test_cli.py index 8cedd088..56297fdf 100644 --- a/tests/test_ipalib/test_cli.py +++ b/tests/test_ipalib/test_cli.py @@ -148,12 +148,12 @@ class test_CLI(ClassChecker): assert o.api is api assert o.argv == tuple(argv) - def test_run(self): + def test_run_real(self): """ - Test the `ipalib.cli.CLI.run` method. + Test the `ipalib.cli.CLI.run_real` method. """ self.check_cascade( - 'run', + 'run_real', 'finalize', 'load_plugins', 'bootstrap', -- cgit From 36737c2d913716eb99aece5cc1f6a21234abe46a Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 14 Nov 2008 21:29:46 -0700 Subject: Added frontend.LocalOrRemote command base class for commands like env --- tests/test_ipalib/test_frontend.py | 56 +++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 2a8c08fe..45c6bb80 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -22,7 +22,7 @@ Test the `ipalib.frontend` module. """ from tests.util import raises, getitem, no_set, no_del, read_only -from tests.util import check_TypeError, ClassChecker +from tests.util import check_TypeError, ClassChecker, get_api from ipalib import frontend, backend, plugable, errors, ipa_types, config @@ -796,6 +796,60 @@ class test_Command(ClassChecker): assert o.run.im_func is my_cmd.forward.im_func +class test_LocalOrRemote(ClassChecker): + """ + Test the `ipalib.frontend.LocalOrRemote` class. + """ + _cls = frontend.LocalOrRemote + + def test_init(self): + """ + Test the `ipalib.frontend.LocalOrRemote.__init__` method. + """ + o = self.cls() + o.finalize() + assert list(o.args) == [] + assert list(o.options) == ['server'] + op = o.options.server + assert op.required is True + assert op.default is False + + def test_run(self): + """ + Test the `ipalib.frontend.LocalOrRemote.run` method. + """ + class example(self.cls): + takes_args = ['key?'] + + def forward(self, *args, **options): + return ('forward', args, options) + + def execute(self, *args, **options): + return ('execute', args, options) + + # Test when in_server=False: + (api, home) = get_api(in_server=False) + api.register(example) + api.finalize() + cmd = api.Command.example + assert cmd() == ('execute', (None,), dict(server=False)) + assert cmd('var') == ('execute', (u'var',), dict(server=False)) + assert cmd(server=True) == ('forward', (None,), dict(server=True)) + assert cmd('var', server=True) == \ + ('forward', (u'var',), dict(server=True)) + + # Test when in_server=True (should always call execute): + (api, home) = get_api(in_server=True) + api.register(example) + api.finalize() + cmd = api.Command.example + assert cmd() == ('execute', (None,), dict(server=False)) + assert cmd('var') == ('execute', (u'var',), dict(server=False)) + assert cmd(server=True) == ('execute', (None,), dict(server=True)) + assert cmd('var', server=True) == \ + ('execute', (u'var',), dict(server=True)) + + class test_Object(ClassChecker): """ Test the `ipalib.frontend.Object` class. -- cgit From 9de56d43f054bc5e509e38bda1a048e5af6d73d7 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 14 Nov 2008 21:58:39 -0700 Subject: env plugin now subclasses from RemoteOrLocal --- tests/test_ipalib/test_frontend.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 45c6bb80..771fdb91 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -811,7 +811,7 @@ class test_LocalOrRemote(ClassChecker): assert list(o.args) == [] assert list(o.options) == ['server'] op = o.options.server - assert op.required is True + assert op.required is False assert op.default is False def test_run(self): @@ -832,8 +832,8 @@ class test_LocalOrRemote(ClassChecker): api.register(example) api.finalize() cmd = api.Command.example - assert cmd() == ('execute', (None,), dict(server=False)) - assert cmd('var') == ('execute', (u'var',), dict(server=False)) + assert cmd() == ('execute', (None,), dict(server=None)) + assert cmd('var') == ('execute', (u'var',), dict(server=None)) assert cmd(server=True) == ('forward', (None,), dict(server=True)) assert cmd('var', server=True) == \ ('forward', (u'var',), dict(server=True)) @@ -843,8 +843,8 @@ class test_LocalOrRemote(ClassChecker): api.register(example) api.finalize() cmd = api.Command.example - assert cmd() == ('execute', (None,), dict(server=False)) - assert cmd('var') == ('execute', (u'var',), dict(server=False)) + assert cmd() == ('execute', (None,), dict(server=None)) + assert cmd('var') == ('execute', (u'var',), dict(server=None)) assert cmd(server=True) == ('execute', (None,), dict(server=True)) assert cmd('var', server=True) == \ ('execute', (u'var',), dict(server=True)) -- cgit From 8474bd01da13b9b72ba06e832d4c35ef6ccf5c9e Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 17 Nov 2008 18:50:30 -0700 Subject: Command.get_defaults() now returns param.default if param.type is a Bool --- tests/test_ipalib/test_frontend.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 771fdb91..44d8e54c 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -832,8 +832,8 @@ class test_LocalOrRemote(ClassChecker): api.register(example) api.finalize() cmd = api.Command.example - assert cmd() == ('execute', (None,), dict(server=None)) - assert cmd('var') == ('execute', (u'var',), dict(server=None)) + assert cmd() == ('execute', (None,), dict(server=False)) + assert cmd('var') == ('execute', (u'var',), dict(server=False)) assert cmd(server=True) == ('forward', (None,), dict(server=True)) assert cmd('var', server=True) == \ ('forward', (u'var',), dict(server=True)) @@ -843,8 +843,8 @@ class test_LocalOrRemote(ClassChecker): api.register(example) api.finalize() cmd = api.Command.example - assert cmd() == ('execute', (None,), dict(server=None)) - assert cmd('var') == ('execute', (u'var',), dict(server=None)) + assert cmd() == ('execute', (None,), dict(server=False)) + assert cmd('var') == ('execute', (u'var',), dict(server=False)) assert cmd(server=True) == ('execute', (None,), dict(server=True)) assert cmd('var', server=True) == \ ('execute', (u'var',), dict(server=True)) -- cgit From 500b8166811e39ac63bdbaee8dcf01eb0643d868 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 18 Nov 2008 16:29:08 -0700 Subject: Added unit test for Param.ispassword() method --- tests/test_ipalib/test_frontend.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 44d8e54c..87296705 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -226,6 +226,22 @@ class test_Param(ClassChecker): 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. -- cgit From cfe4ec2175c42f208ae23401991febb8525bdd9b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 19 Nov 2008 16:11:23 -0700 Subject: Added util.xmlrpc_wrap(), util.xmlrpc_unwrap() functions an corresponding unit tests --- tests/test_ipalib/test_util.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index 6729fcda..b75d6dc7 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -21,6 +21,7 @@ Test the `ipalib.util` module. """ +from xmlrpclib import Binary from tests.util import raises from ipalib import util @@ -49,6 +50,43 @@ def test_xmlrpc_unmarshal(): (('one', 'two'), dict(three=3, four=4)) +def test_xmlrpc_wrap(): + """ + Test the `ipalib.util.xmlrpc_wrap` function. + """ + f = util.xmlrpc_wrap + assert f([]) == tuple() + assert f({}) == dict() + b = f('hello') + assert isinstance(b, Binary) + assert b.data == 'hello' + u = f(u'hello') + assert type(u) is unicode + assert u == u'hello' + value = f([dict(one=False, two=u'hello'), None, 'hello']) + + +def test_xmlrpc_unwrap(): + """ + Test the `ipalib.util.xmlrpc_unwrap` function. + """ + f = util.xmlrpc_unwrap + assert f([]) == tuple() + assert f({}) == dict() + utf8_bytes = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' + unicode_chars = u'\u041f\u0430\u0432\u0435\u043b' + value = f(Binary(utf8_bytes)) + assert type(value) is str + assert value == utf8_bytes + value = f(utf8_bytes) + assert type(value) is unicode + assert value == unicode_chars + value = f([True, Binary('hello'), dict(one=1, two=utf8_bytes, three=None)]) + assert value == (True, 'hello', dict(one=1, two=unicode_chars, three=None)) + assert type(value[1]) is str + assert type(value[2]['two']) is unicode + + def test_make_repr(): """ Test the `ipalib.util.make_repr` function. -- cgit From 75bdea29be8ea53c8e005e9020f3f2d1c7dcf689 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 20 Nov 2008 12:41:06 -0700 Subject: Added test_util.test_round_trip() test that tests use of xmlrpc_wrap() and xmlrpc_unwrap() with dumps(), loads(); fixed a bug in xmlrpc_unwrap() --- tests/test_ipalib/test_util.py | 114 +++++++++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 28 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index b75d6dc7..fd7d85f5 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -21,33 +21,70 @@ Test the `ipalib.util` module. """ -from xmlrpclib import Binary +from xmlrpclib import Binary, dumps, loads +import struct from tests.util import raises from ipalib import util -def test_xmlrpc_marshal(): - """ - Test the `ipalib.util.xmlrpc_marshal` function. - """ - f = util.xmlrpc_marshal - assert f() == ({},) - assert f('one', 'two') == ({}, 'one', 'two') - assert f(one=1, two=2) == (dict(one=1, two=2),) - assert f('one', 'two', three=3, four=4) == \ - (dict(three=3, four=4), 'one', 'two') +# A string that should have bytes 'x\00' through '\xff': +BINARY_BYTES = ''.join(struct.pack('B', d) for d in xrange(256)) +assert '\x00' in BINARY_BYTES and '\xff' in BINARY_BYTES +# A UTF-8 encoded str +UTF8_BYTES = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' -def test_xmlrpc_unmarshal(): +# The same UTF-8 data decoded (a unicode instance) +UNICODE_CHARS = u'\u041f\u0430\u0432\u0435\u043b' +assert UTF8_BYTES.decode('UTF-8') == UNICODE_CHARS +assert UNICODE_CHARS.encode('UTF-8') == UTF8_BYTES +assert UTF8_BYTES != UNICODE_CHARS + + + +def dump_n_load(value): + (param, method) = loads( + dumps((value,)) + ) + return param[0] + + +def round_trip(value): + return util.xmlrpc_unwrap( + dump_n_load(util.xmlrpc_wrap(value)) + ) + + +def test_round_trip(): """ - Test the `ipalib.util.xmlrpc_unmarshal` function. + Test `ipalib.util.xmlrpc_wrap` and `ipalib.util.xmlrpc_unwrap`. + + This tests the two functions together with ``xmlrpclib.dumps`` and + ``xmlrpclib.loads`` in a full encode/decode round trip. """ - f = util.xmlrpc_unmarshal - assert f() == (tuple(), {}) - assert f({}, 'one', 'two') == (('one', 'two'), {}) - assert f(dict(one=1, two=2)) == (tuple(), dict(one=1, two=2)) - assert f(dict(three=3, four=4), 'one', 'two') == \ - (('one', 'two'), dict(three=3, four=4)) + # We first test that our assumptions about xmlrpclib module in the Python + # standard library are correct: + assert dump_n_load(UTF8_BYTES) == UNICODE_CHARS + assert dump_n_load(UNICODE_CHARS) == UNICODE_CHARS + assert dump_n_load(Binary(BINARY_BYTES)).data == BINARY_BYTES + assert isinstance(dump_n_load(Binary(BINARY_BYTES)), Binary) + assert type(dump_n_load('hello')) is str + assert type(dump_n_load(u'hello')) is str + + # Now we test our wrap and unwrap methods in combination with dumps, loads: + # All str should come back str (because they get wrapped in + # xmlrpclib.Binary(). All unicode should come back unicode because str + # explicity get decoded by util.xmlrpc_unwrap() if they weren't already + # decoded by xmlrpclib.loads(). + assert round_trip(UTF8_BYTES) == UTF8_BYTES + assert round_trip(UNICODE_CHARS) == UNICODE_CHARS + assert round_trip(BINARY_BYTES) == BINARY_BYTES + assert type(round_trip('hello')) is str + assert type(round_trip(u'hello')) is unicode + compound = [UTF8_BYTES, UNICODE_CHARS, BINARY_BYTES, + dict(utf8=UTF8_BYTES, chars=UNICODE_CHARS, data=BINARY_BYTES) + ] + assert round_trip(compound) == tuple(compound) def test_xmlrpc_wrap(): @@ -73,20 +110,41 @@ def test_xmlrpc_unwrap(): f = util.xmlrpc_unwrap assert f([]) == tuple() assert f({}) == dict() - utf8_bytes = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' - unicode_chars = u'\u041f\u0430\u0432\u0435\u043b' - value = f(Binary(utf8_bytes)) + value = f(Binary(UTF8_BYTES)) assert type(value) is str - assert value == utf8_bytes - value = f(utf8_bytes) - assert type(value) is unicode - assert value == unicode_chars - value = f([True, Binary('hello'), dict(one=1, two=utf8_bytes, three=None)]) - assert value == (True, 'hello', dict(one=1, two=unicode_chars, three=None)) + assert value == UTF8_BYTES + assert f(UTF8_BYTES) == UNICODE_CHARS + assert f(UNICODE_CHARS) == UNICODE_CHARS + value = f([True, Binary('hello'), dict(one=1, two=UTF8_BYTES, three=None)]) + assert value == (True, 'hello', dict(one=1, two=UNICODE_CHARS, three=None)) assert type(value[1]) is str assert type(value[2]['two']) is unicode +def test_xmlrpc_marshal(): + """ + Test the `ipalib.util.xmlrpc_marshal` function. + """ + f = util.xmlrpc_marshal + assert f() == ({},) + assert f('one', 'two') == ({}, 'one', 'two') + assert f(one=1, two=2) == (dict(one=1, two=2),) + assert f('one', 'two', three=3, four=4) == \ + (dict(three=3, four=4), 'one', 'two') + + +def test_xmlrpc_unmarshal(): + """ + Test the `ipalib.util.xmlrpc_unmarshal` function. + """ + f = util.xmlrpc_unmarshal + assert f() == (tuple(), {}) + assert f({}, 'one', 'two') == (('one', 'two'), {}) + assert f(dict(one=1, two=2)) == (tuple(), dict(one=1, two=2)) + assert f(dict(three=3, four=4), 'one', 'two') == \ + (('one', 'two'), dict(three=3, four=4)) + + def test_make_repr(): """ Test the `ipalib.util.make_repr` function. -- cgit From c02770129db9b27a718dadbf438459c3404c8a5a Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 21 Nov 2008 15:05:39 -0700 Subject: Small changed to test_round_trip() test --- tests/test_ipalib/test_util.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index fd7d85f5..8069d89b 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -30,6 +30,7 @@ from ipalib import util # A string that should have bytes 'x\00' through '\xff': BINARY_BYTES = ''.join(struct.pack('B', d) for d in xrange(256)) assert '\x00' in BINARY_BYTES and '\xff' in BINARY_BYTES +assert type(BINARY_BYTES) is str and len(BINARY_BYTES) == 256 # A UTF-8 encoded str UTF8_BYTES = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' @@ -41,7 +42,6 @@ assert UNICODE_CHARS.encode('UTF-8') == UTF8_BYTES assert UTF8_BYTES != UNICODE_CHARS - def dump_n_load(value): (param, method) = loads( dumps((value,)) @@ -59,8 +59,8 @@ def test_round_trip(): """ Test `ipalib.util.xmlrpc_wrap` and `ipalib.util.xmlrpc_unwrap`. - This tests the two functions together with ``xmlrpclib.dumps`` and - ``xmlrpclib.loads`` in a full encode/decode round trip. + This tests the two functions together with ``xmlrpclib.dumps()`` and + ``xmlrpclib.loads()`` in a full encode/dumps/loads/decode round trip. """ # We first test that our assumptions about xmlrpclib module in the Python # standard library are correct: @@ -81,6 +81,8 @@ def test_round_trip(): assert round_trip(BINARY_BYTES) == BINARY_BYTES assert type(round_trip('hello')) is str assert type(round_trip(u'hello')) is unicode + assert round_trip('') == '' + assert round_trip(u'') == u'' compound = [UTF8_BYTES, UNICODE_CHARS, BINARY_BYTES, dict(utf8=UTF8_BYTES, chars=UNICODE_CHARS, data=BINARY_BYTES) ] -- cgit From 237c16f0fd3998f4a2e69d9096997d10af2cf8c9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 24 Nov 2008 12:51:03 -0700 Subject: Started moving xmlrpc-functions from ipalib.util to ipalib.rpc --- tests/test_ipalib/test_rpc.py | 123 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 tests/test_ipalib/test_rpc.py (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_rpc.py b/tests/test_ipalib/test_rpc.py new file mode 100644 index 00000000..14af2bf4 --- /dev/null +++ b/tests/test_ipalib/test_rpc.py @@ -0,0 +1,123 @@ +# Authors: +# Jason Gerard DeRose +# +# 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.rpc` module. +""" + +from xmlrpclib import Binary, dumps, loads +import struct +from tests.util import raises +from ipalib import rpc + + +# A string that should have bytes 'x\00' through '\xff': +BINARY_BYTES = ''.join(struct.pack('B', d) for d in xrange(256)) +assert '\x00' in BINARY_BYTES and '\xff' in BINARY_BYTES +assert type(BINARY_BYTES) is str and len(BINARY_BYTES) == 256 + +# A UTF-8 encoded str +UTF8_BYTES = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' + +# The same UTF-8 data decoded (a unicode instance) +UNICODE_CHARS = u'\u041f\u0430\u0432\u0435\u043b' +assert UTF8_BYTES.decode('UTF-8') == UNICODE_CHARS +assert UNICODE_CHARS.encode('UTF-8') == UTF8_BYTES +assert UTF8_BYTES != UNICODE_CHARS + + +def dump_n_load(value): + (param, method) = loads( + dumps((value,)) + ) + return param[0] + + +def round_trip(value): + return rpc.xmlrpc_unwrap( + dump_n_load(rpc.xmlrpc_wrap(value)) + ) + + +def test_round_trip(): + """ + Test `ipalib.rpc.xmlrpc_wrap` and `ipalib.rpc.xmlrpc_unwrap`. + + This tests the two functions together with ``xmlrpclib.dumps()`` and + ``xmlrpclib.loads()`` in a full encode/dumps/loads/decode round trip. + """ + # We first test that our assumptions about xmlrpclib module in the Python + # standard library are correct: + assert dump_n_load(UTF8_BYTES) == UNICODE_CHARS + assert dump_n_load(UNICODE_CHARS) == UNICODE_CHARS + assert dump_n_load(Binary(BINARY_BYTES)).data == BINARY_BYTES + assert isinstance(dump_n_load(Binary(BINARY_BYTES)), Binary) + assert type(dump_n_load('hello')) is str + assert type(dump_n_load(u'hello')) is str + + # Now we test our wrap and unwrap methods in combination with dumps, loads: + # All str should come back str (because they get wrapped in + # xmlrpclib.Binary(). All unicode should come back unicode because str + # explicity get decoded by rpc.xmlrpc_unwrap() if they weren't already + # decoded by xmlrpclib.loads(). + assert round_trip(UTF8_BYTES) == UTF8_BYTES + assert round_trip(UNICODE_CHARS) == UNICODE_CHARS + assert round_trip(BINARY_BYTES) == BINARY_BYTES + assert type(round_trip('hello')) is str + assert type(round_trip(u'hello')) is unicode + assert round_trip('') == '' + assert round_trip(u'') == u'' + compound = [UTF8_BYTES, UNICODE_CHARS, BINARY_BYTES, + dict(utf8=UTF8_BYTES, chars=UNICODE_CHARS, data=BINARY_BYTES) + ] + assert round_trip(compound) == tuple(compound) + + +def test_xmlrpc_wrap(): + """ + Test the `ipalib.rpc.xmlrpc_wrap` function. + """ + f = rpc.xmlrpc_wrap + assert f([]) == tuple() + assert f({}) == dict() + b = f('hello') + assert isinstance(b, Binary) + assert b.data == 'hello' + u = f(u'hello') + assert type(u) is unicode + assert u == u'hello' + value = f([dict(one=False, two=u'hello'), None, 'hello']) + + +def test_xmlrpc_unwrap(): + """ + Test the `ipalib.rpc.xmlrpc_unwrap` function. + """ + f = rpc.xmlrpc_unwrap + assert f([]) == tuple() + assert f({}) == dict() + value = f(Binary(UTF8_BYTES)) + assert type(value) is str + assert value == UTF8_BYTES + assert f(UTF8_BYTES) == UNICODE_CHARS + assert f(UNICODE_CHARS) == UNICODE_CHARS + value = f([True, Binary('hello'), dict(one=1, two=UTF8_BYTES, three=None)]) + assert value == (True, 'hello', dict(one=1, two=UNICODE_CHARS, three=None)) + assert type(value[1]) is str + assert type(value[2]['two']) is unicode -- cgit From 2d458a12339fbb7ef006ff7defc1e2f541e2f23f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 24 Nov 2008 21:34:01 -0700 Subject: Stared some RPC-related error cleanup; started work on ipa_server.rcp.xmlrpc plugin --- tests/test_ipalib/test_rpc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_rpc.py b/tests/test_ipalib/test_rpc.py index 14af2bf4..e8d73931 100644 --- a/tests/test_ipalib/test_rpc.py +++ b/tests/test_ipalib/test_rpc.py @@ -32,10 +32,10 @@ BINARY_BYTES = ''.join(struct.pack('B', d) for d in xrange(256)) assert '\x00' in BINARY_BYTES and '\xff' in BINARY_BYTES assert type(BINARY_BYTES) is str and len(BINARY_BYTES) == 256 -# A UTF-8 encoded str +# A UTF-8 encoded str: UTF8_BYTES = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' -# The same UTF-8 data decoded (a unicode instance) +# The same UTF-8 data decoded (a unicode instance): UNICODE_CHARS = u'\u041f\u0430\u0432\u0435\u043b' assert UTF8_BYTES.decode('UTF-8') == UNICODE_CHARS assert UNICODE_CHARS.encode('UTF-8') == UTF8_BYTES @@ -60,7 +60,7 @@ def test_round_trip(): Test `ipalib.rpc.xmlrpc_wrap` and `ipalib.rpc.xmlrpc_unwrap`. This tests the two functions together with ``xmlrpclib.dumps()`` and - ``xmlrpclib.loads()`` in a full encode/dumps/loads/decode round trip. + ``xmlrpclib.loads()`` in a full wrap/dumps/loads/unwrap round trip. """ # We first test that our assumptions about xmlrpclib module in the Python # standard library are correct: -- cgit From 8a2902a2a240108e16561679e01f52b362097b3a Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 8 Dec 2008 12:34:38 -0700 Subject: Re-enable Python2.4 tests and fixed some small things broken under Python2.4 --- tests/test_ipalib/test_rpc.py | 3 ++- tests/test_ipalib/test_util.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_rpc.py b/tests/test_ipalib/test_rpc.py index e8d73931..7af8c220 100644 --- a/tests/test_ipalib/test_rpc.py +++ b/tests/test_ipalib/test_rpc.py @@ -26,6 +26,7 @@ import struct from tests.util import raises from ipalib import rpc +# FIXME: These constants should be imported from tests.data # A string that should have bytes 'x\00' through '\xff': BINARY_BYTES = ''.join(struct.pack('B', d) for d in xrange(256)) @@ -39,7 +40,7 @@ UTF8_BYTES = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' UNICODE_CHARS = u'\u041f\u0430\u0432\u0435\u043b' assert UTF8_BYTES.decode('UTF-8') == UNICODE_CHARS assert UNICODE_CHARS.encode('UTF-8') == UTF8_BYTES -assert UTF8_BYTES != UNICODE_CHARS + def dump_n_load(value): diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index 8069d89b..ef562735 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -21,6 +21,8 @@ Test the `ipalib.util` module. """ +# FIXME: Most of these tests are depreciated and have moved to test_rpc.py + from xmlrpclib import Binary, dumps, loads import struct from tests.util import raises @@ -39,7 +41,6 @@ UTF8_BYTES = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' UNICODE_CHARS = u'\u041f\u0430\u0432\u0435\u043b' assert UTF8_BYTES.decode('UTF-8') == UNICODE_CHARS assert UNICODE_CHARS.encode('UTF-8') == UTF8_BYTES -assert UTF8_BYTES != UNICODE_CHARS def dump_n_load(value): -- cgit From f4f010ae8d2628b09b88b3a995f4b3b008b0608c Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 8 Dec 2008 15:10:01 -0700 Subject: tests.test_ipalib.test_rpc now imports constants from tests.data --- tests/test_ipalib/test_rpc.py | 48 +++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_rpc.py b/tests/test_ipalib/test_rpc.py index 7af8c220..614db607 100644 --- a/tests/test_ipalib/test_rpc.py +++ b/tests/test_ipalib/test_rpc.py @@ -22,26 +22,10 @@ Test the `ipalib.rpc` module. """ from xmlrpclib import Binary, dumps, loads -import struct from tests.util import raises +from tests.data import binary_bytes, utf8_bytes, unicode_str from ipalib import rpc -# FIXME: These constants should be imported from tests.data - -# A string that should have bytes 'x\00' through '\xff': -BINARY_BYTES = ''.join(struct.pack('B', d) for d in xrange(256)) -assert '\x00' in BINARY_BYTES and '\xff' in BINARY_BYTES -assert type(BINARY_BYTES) is str and len(BINARY_BYTES) == 256 - -# A UTF-8 encoded str: -UTF8_BYTES = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' - -# The same UTF-8 data decoded (a unicode instance): -UNICODE_CHARS = u'\u041f\u0430\u0432\u0435\u043b' -assert UTF8_BYTES.decode('UTF-8') == UNICODE_CHARS -assert UNICODE_CHARS.encode('UTF-8') == UTF8_BYTES - - def dump_n_load(value): (param, method) = loads( @@ -65,10 +49,10 @@ def test_round_trip(): """ # We first test that our assumptions about xmlrpclib module in the Python # standard library are correct: - assert dump_n_load(UTF8_BYTES) == UNICODE_CHARS - assert dump_n_load(UNICODE_CHARS) == UNICODE_CHARS - assert dump_n_load(Binary(BINARY_BYTES)).data == BINARY_BYTES - assert isinstance(dump_n_load(Binary(BINARY_BYTES)), Binary) + assert dump_n_load(utf8_bytes) == unicode_str + assert dump_n_load(unicode_str) == unicode_str + assert dump_n_load(Binary(binary_bytes)).data == binary_bytes + assert isinstance(dump_n_load(Binary(binary_bytes)), Binary) assert type(dump_n_load('hello')) is str assert type(dump_n_load(u'hello')) is str @@ -77,15 +61,15 @@ def test_round_trip(): # xmlrpclib.Binary(). All unicode should come back unicode because str # explicity get decoded by rpc.xmlrpc_unwrap() if they weren't already # decoded by xmlrpclib.loads(). - assert round_trip(UTF8_BYTES) == UTF8_BYTES - assert round_trip(UNICODE_CHARS) == UNICODE_CHARS - assert round_trip(BINARY_BYTES) == BINARY_BYTES + assert round_trip(utf8_bytes) == utf8_bytes + assert round_trip(unicode_str) == unicode_str + assert round_trip(binary_bytes) == binary_bytes assert type(round_trip('hello')) is str assert type(round_trip(u'hello')) is unicode assert round_trip('') == '' assert round_trip(u'') == u'' - compound = [UTF8_BYTES, UNICODE_CHARS, BINARY_BYTES, - dict(utf8=UTF8_BYTES, chars=UNICODE_CHARS, data=BINARY_BYTES) + compound = [utf8_bytes, unicode_str, binary_bytes, + dict(utf8=utf8_bytes, chars=unicode_str, data=binary_bytes) ] assert round_trip(compound) == tuple(compound) @@ -113,12 +97,12 @@ def test_xmlrpc_unwrap(): f = rpc.xmlrpc_unwrap assert f([]) == tuple() assert f({}) == dict() - value = f(Binary(UTF8_BYTES)) + value = f(Binary(utf8_bytes)) assert type(value) is str - assert value == UTF8_BYTES - assert f(UTF8_BYTES) == UNICODE_CHARS - assert f(UNICODE_CHARS) == UNICODE_CHARS - value = f([True, Binary('hello'), dict(one=1, two=UTF8_BYTES, three=None)]) - assert value == (True, 'hello', dict(one=1, two=UNICODE_CHARS, three=None)) + assert value == utf8_bytes + assert f(utf8_bytes) == unicode_str + assert f(unicode_str) == unicode_str + value = f([True, Binary('hello'), dict(one=1, two=utf8_bytes, three=None)]) + assert value == (True, 'hello', dict(one=1, two=unicode_str, three=None)) assert type(value[1]) is str assert type(value[2]['two']) is unicode -- cgit From 4591057203e61a4ab304b8730ffede6560f74d4b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 8 Dec 2008 15:15:50 -0700 Subject: Removed depreciated rpc code from ipalib.util; removed corresponding unit tests in test_util --- tests/test_ipalib/test_util.py | 99 ------------------------------------------ 1 file changed, 99 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_util.py b/tests/test_ipalib/test_util.py index ef562735..6729fcda 100644 --- a/tests/test_ipalib/test_util.py +++ b/tests/test_ipalib/test_util.py @@ -21,109 +21,10 @@ Test the `ipalib.util` module. """ -# FIXME: Most of these tests are depreciated and have moved to test_rpc.py - -from xmlrpclib import Binary, dumps, loads -import struct from tests.util import raises from ipalib import util -# A string that should have bytes 'x\00' through '\xff': -BINARY_BYTES = ''.join(struct.pack('B', d) for d in xrange(256)) -assert '\x00' in BINARY_BYTES and '\xff' in BINARY_BYTES -assert type(BINARY_BYTES) is str and len(BINARY_BYTES) == 256 - -# A UTF-8 encoded str -UTF8_BYTES = '\xd0\x9f\xd0\xb0\xd0\xb2\xd0\xb5\xd0\xbb' - -# The same UTF-8 data decoded (a unicode instance) -UNICODE_CHARS = u'\u041f\u0430\u0432\u0435\u043b' -assert UTF8_BYTES.decode('UTF-8') == UNICODE_CHARS -assert UNICODE_CHARS.encode('UTF-8') == UTF8_BYTES - - -def dump_n_load(value): - (param, method) = loads( - dumps((value,)) - ) - return param[0] - - -def round_trip(value): - return util.xmlrpc_unwrap( - dump_n_load(util.xmlrpc_wrap(value)) - ) - - -def test_round_trip(): - """ - Test `ipalib.util.xmlrpc_wrap` and `ipalib.util.xmlrpc_unwrap`. - - This tests the two functions together with ``xmlrpclib.dumps()`` and - ``xmlrpclib.loads()`` in a full encode/dumps/loads/decode round trip. - """ - # We first test that our assumptions about xmlrpclib module in the Python - # standard library are correct: - assert dump_n_load(UTF8_BYTES) == UNICODE_CHARS - assert dump_n_load(UNICODE_CHARS) == UNICODE_CHARS - assert dump_n_load(Binary(BINARY_BYTES)).data == BINARY_BYTES - assert isinstance(dump_n_load(Binary(BINARY_BYTES)), Binary) - assert type(dump_n_load('hello')) is str - assert type(dump_n_load(u'hello')) is str - - # Now we test our wrap and unwrap methods in combination with dumps, loads: - # All str should come back str (because they get wrapped in - # xmlrpclib.Binary(). All unicode should come back unicode because str - # explicity get decoded by util.xmlrpc_unwrap() if they weren't already - # decoded by xmlrpclib.loads(). - assert round_trip(UTF8_BYTES) == UTF8_BYTES - assert round_trip(UNICODE_CHARS) == UNICODE_CHARS - assert round_trip(BINARY_BYTES) == BINARY_BYTES - assert type(round_trip('hello')) is str - assert type(round_trip(u'hello')) is unicode - assert round_trip('') == '' - assert round_trip(u'') == u'' - compound = [UTF8_BYTES, UNICODE_CHARS, BINARY_BYTES, - dict(utf8=UTF8_BYTES, chars=UNICODE_CHARS, data=BINARY_BYTES) - ] - assert round_trip(compound) == tuple(compound) - - -def test_xmlrpc_wrap(): - """ - Test the `ipalib.util.xmlrpc_wrap` function. - """ - f = util.xmlrpc_wrap - assert f([]) == tuple() - assert f({}) == dict() - b = f('hello') - assert isinstance(b, Binary) - assert b.data == 'hello' - u = f(u'hello') - assert type(u) is unicode - assert u == u'hello' - value = f([dict(one=False, two=u'hello'), None, 'hello']) - - -def test_xmlrpc_unwrap(): - """ - Test the `ipalib.util.xmlrpc_unwrap` function. - """ - f = util.xmlrpc_unwrap - assert f([]) == tuple() - assert f({}) == dict() - value = f(Binary(UTF8_BYTES)) - assert type(value) is str - assert value == UTF8_BYTES - assert f(UTF8_BYTES) == UNICODE_CHARS - assert f(UNICODE_CHARS) == UNICODE_CHARS - value = f([True, Binary('hello'), dict(one=1, two=UTF8_BYTES, three=None)]) - assert value == (True, 'hello', dict(one=1, two=UNICODE_CHARS, three=None)) - assert type(value[1]) is str - assert type(value[2]['two']) is unicode - - def test_xmlrpc_marshal(): """ Test the `ipalib.util.xmlrpc_marshal` function. -- cgit From 7e21ea5ad826e65da10d7a12917fd4d0d4f1874e Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 8 Dec 2008 16:56:24 -0700 Subject: Fixed Warning messages about log dir in unit test --- tests/test_ipalib/test_frontend.py | 28 +++++++--------------------- tests/test_ipalib/test_plugable.py | 7 ++++--- 2 files changed, 11 insertions(+), 24 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 87296705..94e586fe 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -22,7 +22,7 @@ Test the `ipalib.frontend` module. """ from tests.util import raises, getitem, no_set, no_del, read_only -from tests.util import check_TypeError, ClassChecker, get_api +from tests.util import check_TypeError, ClassChecker, create_test_api from ipalib import frontend, backend, plugable, errors, ipa_types, config @@ -790,9 +790,7 @@ class test_Command(ClassChecker): kw = dict(how_are='you', on_this='fine day?') # Test in server context: - api = plugable.API(self.cls) - #api.env.update(dict(server_context=True)) - api.env.in_server = True + (api, home) = create_test_api(in_server=True) api.finalize() o = my_cmd() o.set_api(api) @@ -801,9 +799,7 @@ class test_Command(ClassChecker): assert o.run.im_func is my_cmd.execute.im_func # Test in non-server context - api = plugable.API(self.cls) - #api.env.update(dict(server_context=False)) - api.env.in_server = False + (api, home) = create_test_api(in_server=False) api.finalize() o = my_cmd() o.set_api(api) @@ -844,7 +840,7 @@ class test_LocalOrRemote(ClassChecker): return ('execute', args, options) # Test when in_server=False: - (api, home) = get_api(in_server=False) + (api, home) = create_test_api(in_server=False) api.register(example) api.finalize() cmd = api.Command.example @@ -855,7 +851,7 @@ class test_LocalOrRemote(ClassChecker): ('forward', (u'var',), dict(server=True)) # Test when in_server=True (should always call execute): - (api, home) = get_api(in_server=True) + (api, home) = create_test_api(in_server=True) api.register(example) api.finalize() cmd = api.Command.example @@ -986,11 +982,7 @@ class test_Object(ClassChecker): """ Test the `ipalib.frontend.Object.primary_key` attribute. """ - api = plugable.API( - frontend.Method, - frontend.Property, - ) - #config.set_default_env(api.env) + (api, home) = create_test_api() api.finalize() # Test with no primary keys: @@ -1041,13 +1033,7 @@ class test_Object(ClassChecker): """ Test the `ipalib.frontend.Object.backend` attribute. """ - api = plugable.API( - frontend.Object, - frontend.Method, - frontend.Property, - backend.Backend, - ) - #config.set_default_env(api.env) + (api, home) = create_test_api() class ldap(backend.Backend): whatever = 'It worked!' api.register(ldap) diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index ce0c79a9..6b3b3e6c 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -23,7 +23,7 @@ Test the `ipalib.plugable` module. from tests.util import raises, no_set, no_del, read_only from tests.util import getitem, setitem, delitem -from tests.util import ClassChecker, get_api +from tests.util import ClassChecker, create_test_api from ipalib import plugable, errors @@ -860,6 +860,7 @@ class test_API(ClassChecker): class NoProxy(plugable.Plugin): __proxy__ = False api = plugable.API(NoProxy) + api.env.mode = 'unit_test' class plugin0(NoProxy): pass api.register(plugin0) @@ -879,7 +880,7 @@ class test_API(ClassChecker): """ Test the `ipalib.plugable.API.bootstrap` method. """ - (o, home) = get_api() + (o, home) = create_test_api() assert o.env._isdone('_bootstrap') is False assert o.env._isdone('_finalize_core') is False assert o.isdone('bootstrap') is False @@ -895,7 +896,7 @@ class test_API(ClassChecker): """ Test the `ipalib.plugable.API.load_plugins` method. """ - (o, home) = get_api() + (o, home) = create_test_api() assert o.isdone('bootstrap') is False assert o.isdone('load_plugins') is False o.load_plugins() -- cgit From 22209a0f0333526fe953a66f6ea4dd1be18dddc6 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 10 Dec 2008 21:14:05 -0700 Subject: Started roughing out the consolidated type/parameter system in parameters.py; started corresponding unit tests --- tests/test_ipalib/test_parameter.py | 93 +++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 tests/test_ipalib/test_parameter.py (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py new file mode 100644 index 00000000..837bdfef --- /dev/null +++ b/tests/test_ipalib/test_parameter.py @@ -0,0 +1,93 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 +from tests.data import binary_bytes, utf8_bytes, unicode_str +from ipalib import parameter + + +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)) + + +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.name is name + assert o.__islocked__() is True + + 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_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 + + 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 -- cgit From 5c47b56d14d56b825cbfe6a06e056bb98fbb2378 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 11 Dec 2008 18:07:54 -0700 Subject: Finished kwarg validation and extension mechanism in parameter.Param --- tests/test_ipalib/test_parameter.py | 48 ++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 837bdfef..725ce60a 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -25,6 +25,7 @@ Test the `ipalib.parameter` module. from tests.util import raises, ClassChecker from tests.data import binary_bytes, utf8_bytes, unicode_str from ipalib import parameter +from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR def test_parse_param_spec(): @@ -49,24 +50,65 @@ class test_Param(ClassChecker): Test the `ipalib.parameter.Param.__init__` method. """ name = 'my_param' - o = self.cls(name) + o = self.cls(name, {}) assert o.name is name + # assert o.cli_name is name + 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() assert o.__islocked__() is True + kwarg = dict(convert=(callable, None)) + e = raises(ValueError, self.cls, name, kwarg) + assert str(e) == "kwarg 'convert' conflicts with attribute on Param" + class Subclass(self.cls): + pass + e = raises(ValueError, Subclass, name, kwarg) + assert str(e) == "kwarg 'convert' conflicts with attribute on Subclass" + kwargs = dict( + extra1=(bool, True), + extra2=(str, 'Hello'), + extra3=((int, float), 42), + extra4=(callable, lambda whatever: whatever + 7), + ) + # Check that we don't accept None if kind is bool: + e = raises(TypeError, self.cls, 'my_param', kwargs, extra1=None) + assert str(e) == TYPE_ERROR % ('extra1', bool, None, type(None)) + for (key, (kind, default)) in kwargs.items(): + o = self.cls('my_param', kwargs) + # Test with a type invalid for all: + value = object() + overrides = {key: value} + e = raises(TypeError, self.cls, 'my_param', kwargs, **overrides) + if kind is callable: + assert str(e) == CALLABLE_ERROR % (key, value, type(value)) + else: + assert str(e) == TYPE_ERROR % (key, kind, value, type(value)) + if kind is bool: + continue + # Test with None: + overrides = {key: None} + o = self.cls('my_param', kwargs, **overrides) def test_convert_scalar(self): """ Test the `ipalib.parameter.Param._convert_scalar` method. """ - o = self.cls('my_param') + 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') + o = Subclass('my_param', {}) e = raises(NotImplementedError, o._convert_scalar, 'some value') assert str(e) == 'Subclass._convert_scalar()' + class test_Str(ClassChecker): """ Test the `ipalib.parameter.Str` class. -- cgit From 64ae4bc986176383f8aed1c1272edf0031e99d71 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 11 Dec 2008 20:30:59 -0700 Subject: Copied DefaultFrom into parameter.py; added docstring to new Param.normalize() method; more work and unit tests in new Param class --- tests/test_ipalib/test_parameter.py | 72 ++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 5 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 725ce60a..84e9fc0e 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -22,12 +22,67 @@ Test the `ipalib.parameter` module. """ -from tests.util import raises, ClassChecker +from tests.util import raises, ClassChecker, read_only from tests.data import binary_bytes, utf8_bytes, unicode_str from ipalib import parameter from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR +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') + + 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. @@ -51,8 +106,11 @@ class test_Param(ClassChecker): """ name = 'my_param' o = self.cls(name, {}) + assert o.__islocked__() is True + + # Test default values: assert o.name is name - # assert o.cli_name is name + assert o.cli_name is name assert o.doc == '' assert o.required is True assert o.multivalue is False @@ -61,7 +119,9 @@ class test_Param(ClassChecker): assert o.default is None assert o.default_from is None assert o.flags == frozenset() - assert o.__islocked__() is True + + # Test that ValueError is raised when a kwarg from a subclass + # conflicts with an attribute: kwarg = dict(convert=(callable, None)) e = raises(ValueError, self.cls, name, kwarg) assert str(e) == "kwarg 'convert' conflicts with attribute on Param" @@ -69,13 +129,15 @@ class test_Param(ClassChecker): pass e = raises(ValueError, Subclass, name, kwarg) assert str(e) == "kwarg 'convert' conflicts with attribute on Subclass" + + # Test type validation of keyword arguments: kwargs = dict( extra1=(bool, True), extra2=(str, 'Hello'), extra3=((int, float), 42), extra4=(callable, lambda whatever: whatever + 7), ) - # Check that we don't accept None if kind is bool: + # Note: we don't accept None if kind is bool: e = raises(TypeError, self.cls, 'my_param', kwargs, extra1=None) assert str(e) == TYPE_ERROR % ('extra1', bool, None, type(None)) for (key, (kind, default)) in kwargs.items(): @@ -88,7 +150,7 @@ class test_Param(ClassChecker): assert str(e) == CALLABLE_ERROR % (key, value, type(value)) else: assert str(e) == TYPE_ERROR % (key, kind, value, type(value)) - if kind is bool: + if kind is bool: # See note above continue # Test with None: overrides = {key: None} -- cgit From 079721da2cfdd9bc040f7fe6e2842a4775e0e964 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 11 Dec 2008 22:39:50 -0700 Subject: New Param: changed kwargs class attribute to a tuple so the subclass interface is simpler --- tests/test_ipalib/test_parameter.py | 55 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 84e9fc0e..f72c4e62 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -92,6 +92,8 @@ def test_parse_param_spec(): 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 treated special: + assert f('name^') == ('name^', dict(required=True, multivalue=False)) class test_Param(ClassChecker): @@ -105,72 +107,67 @@ class test_Param(ClassChecker): Test the `ipalib.parameter.Param.__init__` method. """ name = 'my_param' - o = self.cls(name, {}) + o = self.cls(name) + assert o.name is name assert o.__islocked__() is True - # Test default values: - assert o.name is name + # Test default kwarg values: assert o.cli_name is name 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 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: - kwarg = dict(convert=(callable, None)) - e = raises(ValueError, self.cls, name, kwarg) - assert str(e) == "kwarg 'convert' conflicts with attribute on Param" class Subclass(self.cls): - pass - e = raises(ValueError, Subclass, name, kwarg) + 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: - kwargs = dict( - extra1=(bool, True), - extra2=(str, 'Hello'), - extra3=((int, float), 42), - extra4=(callable, lambda whatever: whatever + 7), - ) - # Note: we don't accept None if kind is bool: - e = raises(TypeError, self.cls, 'my_param', kwargs, extra1=None) - assert str(e) == TYPE_ERROR % ('extra1', bool, None, type(None)) - for (key, (kind, default)) in kwargs.items(): - o = self.cls('my_param', kwargs) + 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() - overrides = {key: value} - e = raises(TypeError, self.cls, 'my_param', kwargs, **overrides) + 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)) - if kind is bool: # See note above - continue + # Test with None: - overrides = {key: None} - o = self.cls('my_param', kwargs, **overrides) + kw = {key: None} + Subclass('my_param', **kw) def test_convert_scalar(self): """ Test the `ipalib.parameter.Param._convert_scalar` method. """ - o = self.cls('my_param', {}) + 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', {}) + o = Subclass('my_param') e = raises(NotImplementedError, o._convert_scalar, 'some value') assert str(e) == 'Subclass._convert_scalar()' - class test_Str(ClassChecker): """ Test the `ipalib.parameter.Str` class. -- cgit From 5272949bfd01b9648902fd9dea77762d06d52832 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 12 Dec 2008 03:13:58 -0700 Subject: New Param: added all logic for minlength, maxlength, and length in Bytes class (which Str inherits) --- tests/test_ipalib/test_parameter.py | 57 ++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index f72c4e62..ddc938d4 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -149,11 +149,12 @@ class test_Param(ClassChecker): 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: + def test_convert_scalar(self): """ Test the `ipalib.parameter.Param._convert_scalar` method. @@ -168,6 +169,56 @@ class test_Param(ClassChecker): 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.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 + permutations = [ + dict(minlength=3), + dict(maxlength=7), + dict(minlength=3, maxlength=7), + ] + for kw in permutations: + o = self.cls('my_bytes', **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" + + class test_Str(ClassChecker): """ Test the `ipalib.parameter.Str` class. @@ -180,6 +231,10 @@ class test_Str(ClassChecker): """ 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): """ -- cgit From 66faffdfb09ee2bcee1b405c78b37e340bc043aa Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 12 Dec 2008 03:38:02 -0700 Subject: New Param: cleanup up readability of Param.__init__(); added unit tests for unknown kwargs --- tests/test_ipalib/test_parameter.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index ddc938d4..855e2cbc 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -154,6 +154,15 @@ class test_Param(ClassChecker): 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_convert_scalar(self): """ -- cgit From e05fd7ab03eb05c26e880ae04fbf095198b58027 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 12 Dec 2008 04:48:25 -0700 Subject: New Param: added basic rule logic --- tests/test_ipalib/test_parameter.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 855e2cbc..23b81f28 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -92,7 +92,7 @@ def test_parse_param_spec(): 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 treated special: + # Make sure other "funny" endings are *not* treated special: assert f('name^') == ('name^', dict(required=True, multivalue=False)) @@ -111,6 +111,9 @@ class test_Param(ClassChecker): assert o.name is name assert o.__islocked__() is True + # Test default rules: + assert o.rules == tuple() + # Test default kwarg values: assert o.cli_name is name assert o.doc == '' @@ -118,7 +121,7 @@ class test_Param(ClassChecker): assert o.multivalue is False assert o.primary_key is False assert o.normalizer is None - #assert o.default is None + assert o.default is None assert o.default_from is None assert o.flags == frozenset() @@ -190,6 +193,7 @@ class test_Bytes(ClassChecker): """ o = self.cls('my_bytes') assert o.type is str + assert o.rules == tuple() assert o.minlength is None assert o.maxlength is None assert o.length is None @@ -198,6 +202,7 @@ class test_Bytes(ClassChecker): # Test mixing length with minlength or maxlength: o = self.cls('my_bytes', length=5) assert o.length == 5 + assert len(o.rules) == 1 permutations = [ dict(minlength=3), dict(maxlength=7), @@ -205,6 +210,7 @@ class test_Bytes(ClassChecker): ] for kw in permutations: o = self.cls('my_bytes', **kw) + assert len(o.rules) == len(kw) for (key, value) in kw.iteritems(): assert getattr(o, key) == value e = raises(ValueError, self.cls, 'my_bytes', length=5, **kw) -- cgit From ba481e7712b9d92694a38399936fd0eceef93cb6 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 17 Dec 2008 18:32:46 -0700 Subject: New Param: split class_rules and *rules into separate attributes --- tests/test_ipalib/test_parameter.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 23b81f28..508e399f 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -108,11 +108,15 @@ class test_Param(ClassChecker): """ 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 @@ -194,6 +198,8 @@ class test_Bytes(ClassChecker): 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 @@ -202,7 +208,9 @@ class test_Bytes(ClassChecker): # Test mixing length with minlength or maxlength: o = self.cls('my_bytes', length=5) assert o.length == 5 - assert len(o.rules) == 1 + assert len(o.class_rules) == 1 + assert len(o.rules) == 0 + assert len(o.all_rules) == 1 permutations = [ dict(minlength=3), dict(maxlength=7), @@ -210,7 +218,9 @@ class test_Bytes(ClassChecker): ] for kw in permutations: o = self.cls('my_bytes', **kw) - assert len(o.rules) == len(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) -- cgit From 69041c3b1b2494d89097e490048c23292c8cbc52 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 17 Dec 2008 21:47:43 -0700 Subject: Removed Plugin.name property and replaced with instance attribute created in Plugin.__init__() --- tests/test_ipalib/test_plugable.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 6b3b3e6c..00dc5241 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -303,19 +303,23 @@ class test_Plugin(ClassChecker): """ assert self.cls.__bases__ == (plugable.ReadOnly,) assert self.cls.__public__ == frozenset() - assert type(self.cls.name) is property assert type(self.cls.doc) is property assert type(self.cls.api) is property - def test_name(self): + def test_init(self): """ - Test the `ipalib.plugable.Plugin.name` property. + Test the `ipalib.plugable.Plugin.__init__` method. """ - assert read_only(self.cls(), 'name') == 'Plugin' - + o = self.cls() + assert o.name == 'Plugin' + assert o.module == 'ipalib.plugable' + assert o.fullname == 'ipalib.plugable.Plugin' class some_subclass(self.cls): pass - assert read_only(some_subclass(), 'name') == 'some_subclass' + o = some_subclass() + assert o.name == 'some_subclass' + assert o.module == __name__ + assert o.fullname == '%s.some_subclass' % __name__ def test_doc(self): """ -- cgit From 171ed58367e58c59f9f67ef831f08ce80ba8508b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 17 Dec 2008 21:57:58 -0700 Subject: Removed Plugin.doc property and replaced with instance attribute created in Plugin.__init__() --- tests/test_ipalib/test_plugable.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 00dc5241..02df058b 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -303,7 +303,6 @@ class test_Plugin(ClassChecker): """ assert self.cls.__bases__ == (plugable.ReadOnly,) assert self.cls.__public__ == frozenset() - assert type(self.cls.doc) is property assert type(self.cls.api) is property def test_init(self): @@ -314,20 +313,20 @@ class test_Plugin(ClassChecker): assert o.name == 'Plugin' assert o.module == 'ipalib.plugable' assert o.fullname == 'ipalib.plugable.Plugin' + assert o.doc == self.cls.__doc__ class some_subclass(self.cls): - pass + """ + Do sub-classy things. + + Although it doesn't know how to comport itself and is not for mixed + company, this class *is* useful as we all need a little sub-class + now and then. + """ o = some_subclass() assert o.name == 'some_subclass' assert o.module == __name__ assert o.fullname == '%s.some_subclass' % __name__ - - def test_doc(self): - """ - Test the `ipalib.plugable.Plugin.doc` property. - """ - class some_subclass(self.cls): - 'here is the doc string' - assert read_only(some_subclass(), 'doc') == 'here is the doc string' + assert o.doc == some_subclass.__doc__ def test_implements(self): """ -- cgit From 4f24f0fd8837383f4a2abc54946f6f84810807b8 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 17 Dec 2008 23:08:52 -0700 Subject: Plugin.doc instance attribute is now parsed out using inspect.getdoc(); added Plugin.summary instance attribute, created in Plugin.__init__() --- tests/test_ipalib/test_plugable.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 02df058b..21c71280 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -21,6 +21,7 @@ Test the `ipalib.plugable` module. """ +import inspect from tests.util import raises, no_set, no_del, read_only from tests.util import getitem, setitem, delitem from tests.util import ClassChecker, create_test_api @@ -313,7 +314,7 @@ class test_Plugin(ClassChecker): assert o.name == 'Plugin' assert o.module == 'ipalib.plugable' assert o.fullname == 'ipalib.plugable.Plugin' - assert o.doc == self.cls.__doc__ + assert o.doc == inspect.getdoc(self.cls) class some_subclass(self.cls): """ Do sub-classy things. @@ -321,12 +322,20 @@ class test_Plugin(ClassChecker): Although it doesn't know how to comport itself and is not for mixed company, this class *is* useful as we all need a little sub-class now and then. + + One more paragraph. """ o = some_subclass() assert o.name == 'some_subclass' assert o.module == __name__ assert o.fullname == '%s.some_subclass' % __name__ - assert o.doc == some_subclass.__doc__ + assert o.doc == inspect.getdoc(some_subclass) + assert o.summary == 'Do sub-classy things.' + class another_subclass(self.cls): + pass + o = another_subclass() + assert o.doc is None + assert o.summary == '<%s>' % o.fullname def test_implements(self): """ -- cgit From bf8154fa5017d12c7377175f85f60b670dc294f9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 18 Dec 2008 00:02:38 -0700 Subject: New Param: fixed a few things in Param.convert() and added corresponding unit tests --- tests/test_ipalib/test_parameter.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 508e399f..7d931583 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -25,7 +25,7 @@ Test the `ipalib.parameter` module. from tests.util import raises, ClassChecker, read_only from tests.data import binary_bytes, utf8_bytes, unicode_str from ipalib import parameter -from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR +from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR, NULLS class test_DefaultFrom(ClassChecker): @@ -171,6 +171,35 @@ class test_Param(ClassChecker): assert str(e) == \ "Param('my_param'): takes no such kwargs: 'ape', 'great'" + 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. -- cgit From ac335bc7ea5ca290a25b9ac27e17f1b68bd8b4a9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 18 Dec 2008 01:18:17 -0700 Subject: New Param: fixed small bug in Param.convert() and added detailed docstring --- tests/test_ipalib/test_parameter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 7d931583..5ee9e8ca 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -297,7 +297,7 @@ class test_Str(ClassChecker): 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')): + 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 -- cgit From cb2f294cfef9b47e03b82c85cf1db7e7bc3574ef Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 18 Dec 2008 01:57:39 -0700 Subject: New Param: added missing unit tests for TypeError and ValueError cases in parse_param_spec() --- tests/test_ipalib/test_parameter.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 5ee9e8ca..4fc9a0e7 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -92,9 +92,18 @@ def test_parse_param_spec(): 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): """ -- cgit From 4d1681176afc45c57fb4316892f939bda1bacf1d Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 18 Dec 2008 02:08:41 -0700 Subject: New Param: added unit tests for TypeError cases in DefaultFrom.__init__() --- tests/test_ipalib/test_parameter.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 4fc9a0e7..d7f8e45c 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -48,6 +48,14 @@ class test_DefaultFrom(ClassChecker): 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. -- cgit From 46e37ab14491db06ffa46b682c079c397e644014 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 18 Dec 2008 11:21:12 -0700 Subject: New Param: ported Param.__repr__() and corresponding unit test --- tests/test_ipalib/test_parameter.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index d7f8e45c..ef248b70 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -188,6 +188,18 @@ class test_Param(ClassChecker): 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_convert(self): """ Test the `ipalib.parameter.Param.convert` method. -- cgit From dc54dee622bf9ff95a59530423ac5caa01868373 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 18 Dec 2008 14:01:59 -0700 Subject: Started work on per-request gettext setup --- tests/test_ipalib/test_request.py | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/test_ipalib/test_request.py (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_request.py b/tests/test_ipalib/test_request.py new file mode 100644 index 00000000..7ccf9b82 --- /dev/null +++ b/tests/test_ipalib/test_request.py @@ -0,0 +1,56 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 Red Hat +# see file 'COPYING' for use and warranty contextrmation +# +# 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.request` module. +""" + +import locale +from tests.util import raises +from ipalib.constants import OVERRIDE_ERROR +from ipalib import request + + +def test_set_languages(): + """ + Test the `ipalib.request.set_languages` function. + """ + f = request.set_languages + c = request.context + langs = ('ru', 'en') + + # Test that StandardError is raised if languages has already been set: + assert not hasattr(c, 'languages') + c.languages = None + e = raises(StandardError, f, *langs) + assert str(e) == OVERRIDE_ERROR % ('context.languages', None, langs) + del c.languages + + # Test setting the languages: + assert not hasattr(c, 'languages') + f(*langs) + assert c.languages == langs + del c.languages + + # Test setting language from locale.getdefaultlocale() + assert not hasattr(c, 'languages') + f() + assert c.languages == locale.getdefaultlocale()[:1] + del c.languages + assert not hasattr(c, 'languages') -- cgit From 9a69adeef001ddd0c55513271cf02eedc0a9aef8 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 18 Dec 2008 16:58:48 -0700 Subject: Added request.create_translation() function and corresponding unit tests --- tests/test_ipalib/test_request.py | 45 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_request.py b/tests/test_ipalib/test_request.py index 7ccf9b82..1b9c9e3d 100644 --- a/tests/test_ipalib/test_request.py +++ b/tests/test_ipalib/test_request.py @@ -21,8 +21,9 @@ Test the `ipalib.request` module. """ +import threading import locale -from tests.util import raises +from tests.util import raises, TempDir from ipalib.constants import OVERRIDE_ERROR from ipalib import request @@ -54,3 +55,45 @@ def test_set_languages(): assert c.languages == locale.getdefaultlocale()[:1] del c.languages assert not hasattr(c, 'languages') + + +def test_create_translation(): + """ + Test the `ipalib.request.create_translation` function. + """ + f = request.create_translation + c = request.context + t = TempDir() + + # Test that StandardError is raised if gettext or ngettext: + assert not (hasattr(c, 'gettext') or hasattr(c, 'ngettext')) + for name in 'gettext', 'ngettext': + setattr(c, name, None) + e = raises(StandardError, f, 'ipa', None) + assert str(e) == ( + 'create_translation() already called in thread %r' % + threading.currentThread().getName() + ) + delattr(c, name) + + # Test using default language: + assert not hasattr(c, 'gettext') + assert not hasattr(c, 'ngettext') + assert not hasattr(c, 'languages') + f('ipa', t.path) + assert hasattr(c, 'gettext') + assert hasattr(c, 'ngettext') + assert c.languages == locale.getdefaultlocale()[:1] + del c.gettext + del c.ngettext + del c.languages + + # Test using explicit languages: + langs = ('de', 'es') + f('ipa', t.path, *langs) + assert hasattr(c, 'gettext') + assert hasattr(c, 'ngettext') + assert c.languages == langs + del c.gettext + del c.ngettext + del c.languages -- cgit From 4390523b7f854cefcb91843e1df3ca7575d43fea Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 21 Dec 2008 17:12:00 -0700 Subject: Improved Plugin.call() method and added its unit test --- tests/test_ipalib/test_plugable.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 21c71280..b381675b 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -452,6 +452,18 @@ class test_Plugin(ClassChecker): o.finalize() assert o.__islocked__() + def test_call(self): + """ + Test the `ipalib.plugable.Plugin.call` method. + """ + o = self.cls() + o.call('/bin/true') is None + e = raises(errors.SubprocessError, o.call, '/bin/false') + assert str(e) == 'return code %d from %r' % (1, ('/bin/false',)) + assert e.returncode == 1 + assert e.argv == ('/bin/false',) + + class test_PluginProxy(ClassChecker): """ -- cgit From 9d091c98f1f1bf7bacf49e9eaaa18ba8bb1bfd70 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 21 Dec 2008 19:34:32 -0700 Subject: Plugin.__init__() now checks that subclass hasn't defined attributes that conflict with the logger methods; added corresponding unit test --- tests/test_ipalib/test_plugable.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index b381675b..b0594323 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -337,6 +337,14 @@ class test_Plugin(ClassChecker): assert o.doc is None assert o.summary == '<%s>' % o.fullname + # Test that Plugin makes sure the subclass hasn't defined attributes + # whose names conflict with the logger methods set in Plugin.__init__(): + class check(self.cls): + info = 'whatever' + e = raises(StandardError, check) + assert str(e) == \ + "check.info attribute ('whatever') conflicts with Plugin logger" + def test_implements(self): """ Test the `ipalib.plugable.Plugin.implements` classmethod. -- cgit From 5b637f6a18a647a0ff084b2932faa1a4a887a5c2 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 22 Dec 2008 15:41:24 -0700 Subject: Removed depreciated code from config.py; removed corresponding unit tests --- tests/test_ipalib/test_config.py | 162 +-------------------------------------- 1 file changed, 1 insertion(+), 161 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index ddfbb708..e17c4799 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -31,88 +31,7 @@ from tests.util import TempDir, TempHome from ipalib import config, constants -def test_Environment(): - """ - Test the `ipalib.config.Environment` class. - """ - # This has to be the same as iter_cnt - control_cnt = 0 - class prop_class: - def __init__(self, val): - self._val = val - def get_value(self): - return self._val - - class iter_class(prop_class): - # Increment this for each time iter_class yields - iter_cnt = 0 - def get_value(self): - for item in self._val: - self.__class__.iter_cnt += 1 - yield item - - # Tests for basic functionality - basic_tests = ( - ('a', 1), - ('b', 'basic_foo'), - ('c', ('basic_bar', 'basic_baz')), - ) - # Tests with prop classes - prop_tests = ( - ('d', prop_class(2), 2), - ('e', prop_class('prop_foo'), 'prop_foo'), - ('f', prop_class(('prop_bar', 'prop_baz')), ('prop_bar', 'prop_baz')), - ) - # Tests with iter classes - iter_tests = ( - ('g', iter_class((3, 4, 5)), (3, 4, 5)), - ('h', iter_class(('iter_foo', 'iter_bar', 'iter_baz')), - ('iter_foo', 'iter_bar', 'iter_baz') - ), - ) - - # Set all the values - env = config.Environment() - for name, val in basic_tests: - env[name] = val - for name, val, dummy in prop_tests: - env[name] = val - for name, val, dummy in iter_tests: - env[name] = val - - # Test if the values are correct - for name, val in basic_tests: - assert env[name] == val - for name, dummy, val in prop_tests: - assert env[name] == val - # Test if the get_value() function is called only when needed - for name, dummy, correct_values in iter_tests: - values_in_env = [] - for val in env[name]: - control_cnt += 1 - assert iter_class.iter_cnt == control_cnt - values_in_env.append(val) - assert tuple(values_in_env) == correct_values - - # Test __setattr__() - env.spam = 'ham' - - assert env.spam == 'ham' - assert env['spam'] == 'ham' - assert env.get('spam') == 'ham' - assert env.get('nonexistent') == None - assert env.get('nonexistent', 42) == 42 - - # Test if we throw AttributeError exception when trying to overwrite - # existing value, or delete it - raises(AttributeError, setitem, env, 'a', 1) - raises(AttributeError, setattr, env, 'a', 1) - raises(AttributeError, delitem, env, 'a') - raises(AttributeError, delattr, env, 'a') - raises(AttributeError, config.Environment.update, env, dict(a=1000)) - # This should be silently ignored - env.update(dict(a=1000), True) - assert env.a != 1000 + # Random base64-encoded data to simulate a misbehaving config file. @@ -557,82 +476,3 @@ class test_Env(ClassChecker): for key in keys: o[key] = 'the value' assert list(o) == sorted(keys + default_keys) - - -def test_set_default_env(): - """ - Test the `ipalib.config.set_default_env` function. - """ - - # Make sure we don't overwrite any properties - d = dict( - query_dns = False, - server = ('first', 'second'), - realm = 'myrealm', - # test right conversions - server_context = 'off', - ) - env = config.Environment() - config.set_default_env(env) - env.update(d) - assert env['server_context'] == False - assert env['query_dns'] == False - - # Make sure the servers is overwrote properly (that it is still LazyProp) - iter = env['server'] - assert iter.next() == 'first' - assert iter.next() == 'second' - - -def test_LazyProp(): - """ - Test the `ipalib.config.LazyProp` class. - """ - - def dummy(): - return 1 - - # Basic sanity testing with no initial value - prop = config.LazyProp(int, dummy) - assert prop.get_value() == 1 - prop.set_value(2) - assert prop.get_value() == 2 - - # Basic sanity testing with initial value - prop = config.LazyProp(int, dummy, 3) - assert prop.get_value() == 3 - prop.set_value(4) - assert prop.get_value() == 4 - - -def test_LazyIter(): - """ - Test the `ipalib.config.LazyIter` class. - """ - - def dummy(): - yield 1 - yield 2 - - # Basic sanity testing with no initial value - prop = config.LazyIter(int, dummy) - iter = prop.get_value() - assert iter.next() == 1 - assert iter.next() == 2 - raises(StopIteration, iter.next) - - # Basic sanity testing with initial value - prop = config.LazyIter(int, dummy, 0) - iter = prop.get_value() - assert iter.next() == 0 - assert iter.next() == 1 - assert iter.next() == 2 - raises(StopIteration, iter.next) - - -def test_read_config(): - """ - Test the `ipalib.config.read_config` class. - """ - - raises(AssertionError, config.read_config, 1) -- cgit From c070d390e92df0c9cc6b6070e6c94bd3a130ff65 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 22 Dec 2008 15:51:54 -0700 Subject: Removed Env.__getattr__(); Env no longer accepts callables for values (no more dynamic/lazy values) --- tests/test_ipalib/test_config.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index e17c4799..6c70aeb9 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -374,23 +374,16 @@ class test_Env(ClassChecker): e = raises(StandardError, o.__lock__) assert str(e) == 'Env.__lock__() already called' - def test_getattr(self): + def test_getitem(self): """ - Test the `ipalib.config.Env.__getattr__` method. - - Also tests the `ipalib.config.Env.__getitem__` method. + Test the `ipalib.config.Env.__getitem__` method. """ o = self.cls() value = 'some value' o.key = value assert o.key is value assert o['key'] is value - o.call = lambda: 'whatever' - assert o.call == 'whatever' - assert o['call'] == 'whatever' for name in ('one', 'two'): - e = raises(AttributeError, getattr, o, name) - assert str(e) == 'Env.%s' % name e = raises(KeyError, getitem, o, name) assert str(e) == repr(name) @@ -402,9 +395,9 @@ class test_Env(ClassChecker): """ items = [ ('one', 1), - ('two', lambda: 2), + ('two', 2), ('three', 3), - ('four', lambda: 4), + ('four', 4), ] for setvar in (setattr, setitem): o = self.cls() @@ -457,9 +450,9 @@ class test_Env(ClassChecker): o = self.cls() items = [ ('one', 1), - ('two', lambda: 2), + ('two', 2), ('three', 3), - ('four', lambda: 4), + ('four', 4), ] for (key, value) in items: assert key not in o -- cgit From 014cca57ad31f0ff9230923c8b7fdb1b59157dae Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 22 Dec 2008 16:16:57 -0700 Subject: The Env.__setitem__() implied conversion is now case sensitive; Env.__setitem__() now also accepts None as a value --- tests/test_ipalib/test_config.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 6c70aeb9..f92445f8 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -89,8 +89,8 @@ key3 = var3 config_good = """ [global] -yes = tRUE -no = fALse +yes = True +no = False number = 42 """ @@ -157,7 +157,7 @@ class test_Env(ClassChecker): assert o.conf_default == o.conf # Test overriding values created by _bootstrap() - (o, home) = self.bootstrap(in_tree='true', context='server') + (o, home) = self.bootstrap(in_tree='True', context='server') assert o.in_tree is True assert o.context == 'server' assert o.conf == home.join('.ipa', 'server.conf') @@ -243,7 +243,7 @@ class test_Env(ClassChecker): assert o.log == home.join('.ipa', 'log', 'cli.log') # Check **defaults can't set in_server nor log: - (o, home) = self.bootstrap(in_server='tRUE') + (o, home) = self.bootstrap(in_server='True') o._finalize_core(in_server=False) assert o.in_server is True (o, home) = self.bootstrap(log='/some/silly/log') @@ -271,9 +271,9 @@ class test_Env(ClassChecker): (o, home) = self.finalize_core(**defaults) assert list(o) == sorted(defaults) for (key, value) in defaults.items(): - if value is None: + if value is object: continue - assert o[key] is value + assert o[key] is value, value def test_finalize(self): """ @@ -418,9 +418,9 @@ class test_Env(ClassChecker): assert str(e) == \ 'locked: cannot set Env.%s to %r' % (name, value) o = self.cls() - setvar(o, 'yes', ' true ') + setvar(o, 'yes', ' True ') assert o.yes is True - setvar(o, 'no', ' false ') + setvar(o, 'no', ' False ') assert o.no is False setvar(o, 'msg', u' Hello, world! ') assert o.msg == 'Hello, world!' -- cgit From 6b055b435f93bf9b63ee9b3b2fdd6f082dacc07b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 22 Dec 2008 17:29:11 -0700 Subject: Cleaned up Env.__setattr__() and Env.__setitem__() a bit updated their unit tests --- tests/test_ipalib/test_config.py | 110 ++++++++++++++++++++++++-------------- tests/test_ipalib/test_request.py | 2 +- 2 files changed, 72 insertions(+), 40 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index f92445f8..c1a5faaa 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -28,10 +28,33 @@ import sys from tests.util import raises, setitem, delitem, ClassChecker from tests.util import getitem, setitem, delitem from tests.util import TempDir, TempHome +from ipalib.constants import TYPE_ERROR, OVERRIDE_ERROR, LOCK_ERROR from ipalib import config, constants +# Valid environment variables in (key, raw, value) tuples: +# key: the name of the environment variable +# raw: the value being set (possibly a string repr) +# value: the expected value after the lightweight conversion +good_vars = ( + ('a_string', 'Hello world!', 'Hello world!'), + ('trailing_whitespace', ' value ', 'value'), + ('an_int', 42, 42), + ('int_repr', ' 42 ', 42), + ('true', True, True), + ('true_repr', ' True ', True), + ('false', False, False), + ('false_repr', ' False ', False), + ('none', None, None), + ('none_repr', ' None ', None), + + # These verify that the implied conversion is case-sensitive: + ('not_true', ' true ', 'true'), + ('not_false', ' false ', 'false'), + ('not_none', ' none ', 'none'), +) + # Random base64-encoded data to simulate a misbehaving config file. @@ -132,6 +155,54 @@ class test_Env(ClassChecker): assert o.home == home.path assert o.dot_ipa == home.join('.ipa') + def test_setattr(self): + """ + Test the `ipalib.config.Env.__setattr__` method. + """ + o = self.cls() + for (name, raw, value) in good_vars: + # Test setting the value: + setattr(o, name, raw) + result = getattr(o, name) + assert type(result) is type(value) + assert result == value + assert result is o[name] + + # Test that value cannot be overridden once set: + e = raises(AttributeError, setattr, o, name, raw) + assert str(e) == OVERRIDE_ERROR % ('Env', name, value, raw) + + # Test that values cannot be set once locked: + o = self.cls() + o.__lock__() + for (name, raw, value) in good_vars: + e = raises(AttributeError, setattr, o, name, raw) + assert str(e) == LOCK_ERROR % ('Env', name, raw) + + def test_setitem(self): + """ + Test the `ipalib.config.Env.__setitem__` method. + """ + o = self.cls() + for (key, raw, value) in good_vars: + # Test setting the value: + o[key] = raw + result = o[key] + assert type(result) is type(value) + assert result == value + assert result is getattr(o, key) + + # Test that value cannot be overridden once set: + e = raises(AttributeError, o.__setitem__, key, raw) + assert str(e) == OVERRIDE_ERROR % ('Env', key, value, raw) + + # Test that values cannot be set once locked: + o = self.cls() + o.__lock__() + for (key, raw, value) in good_vars: + e = raises(AttributeError, o.__setitem__, key, raw) + assert str(e) == LOCK_ERROR % ('Env', key, raw) + def bootstrap(self, **overrides): (o, home) = self.new() assert o._isdone('_bootstrap') is False @@ -387,46 +458,7 @@ class test_Env(ClassChecker): e = raises(KeyError, getitem, o, name) assert str(e) == repr(name) - def test_setattr(self): - """ - Test the `ipalib.config.Env.__setattr__` method. - Also tests the `ipalib.config.Env.__setitem__` method. - """ - items = [ - ('one', 1), - ('two', 2), - ('three', 3), - ('four', 4), - ] - for setvar in (setattr, setitem): - o = self.cls() - for (i, (name, value)) in enumerate(items): - setvar(o, name, value) - assert getattr(o, name) == i + 1 - assert o[name] == i + 1 - if callable(value): - assert name not in dir(o) - else: - assert name in dir(o) - e = raises(AttributeError, setvar, o, name, 42) - assert str(e) == 'cannot overwrite Env.%s with 42' % name - o = self.cls() - o.__lock__() - for (name, value) in items: - e = raises(AttributeError, setvar, o, name, value) - assert str(e) == \ - 'locked: cannot set Env.%s to %r' % (name, value) - o = self.cls() - setvar(o, 'yes', ' True ') - assert o.yes is True - setvar(o, 'no', ' False ') - assert o.no is False - setvar(o, 'msg', u' Hello, world! ') - assert o.msg == 'Hello, world!' - assert type(o.msg) is str - setvar(o, 'num', ' 42 ') - assert o.num == 42 def test_delattr(self): """ diff --git a/tests/test_ipalib/test_request.py b/tests/test_ipalib/test_request.py index 1b9c9e3d..5efc0abd 100644 --- a/tests/test_ipalib/test_request.py +++ b/tests/test_ipalib/test_request.py @@ -40,7 +40,7 @@ def test_set_languages(): assert not hasattr(c, 'languages') c.languages = None e = raises(StandardError, f, *langs) - assert str(e) == OVERRIDE_ERROR % ('context.languages', None, langs) + assert str(e) == OVERRIDE_ERROR % ('context', 'languages', None, langs) del c.languages # Test setting the languages: -- cgit From 01cae56e0a19876cf6a614469c0c5e6fb73170e6 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 22 Dec 2008 21:02:43 -0700 Subject: Some more reorganization in Env and added class docstring to Env with lots of examples --- tests/test_ipalib/test_config.py | 64 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index c1a5faaa..740ef6cf 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -28,7 +28,7 @@ import sys from tests.util import raises, setitem, delitem, ClassChecker from tests.util import getitem, setitem, delitem from tests.util import TempDir, TempHome -from ipalib.constants import TYPE_ERROR, OVERRIDE_ERROR, LOCK_ERROR +from ipalib.constants import TYPE_ERROR, OVERRIDE_ERROR, SET_ERROR, DEL_ERROR from ipalib import config, constants @@ -177,7 +177,7 @@ class test_Env(ClassChecker): o.__lock__() for (name, raw, value) in good_vars: e = raises(AttributeError, setattr, o, name, raw) - assert str(e) == LOCK_ERROR % ('Env', name, raw) + assert str(e) == SET_ERROR % ('Env', name, raw) def test_setitem(self): """ @@ -201,7 +201,35 @@ class test_Env(ClassChecker): o.__lock__() for (key, raw, value) in good_vars: e = raises(AttributeError, o.__setitem__, key, raw) - assert str(e) == LOCK_ERROR % ('Env', key, raw) + assert str(e) == SET_ERROR % ('Env', key, raw) + + def test_getitem(self): + """ + Test the `ipalib.config.Env.__getitem__` method. + """ + o = self.cls() + value = 'some value' + o.key = value + assert o.key is value + assert o['key'] is value + for name in ('one', 'two'): + e = raises(KeyError, getitem, o, name) + assert str(e) == repr(name) + + def test_delattr(self): + """ + Test the `ipalib.config.Env.__delattr__` method. + + This also tests that ``__delitem__`` is not implemented. + """ + o = self.cls() + o.one = 1 + assert o.one == 1 + for key in ('one', 'two'): + e = raises(AttributeError, delattr, o, key) + assert str(e) == DEL_ERROR % ('Env', key) + e = raises(AttributeError, delitem, o, key) + assert str(e) == '__delitem__' def bootstrap(self, **overrides): (o, home) = self.new() @@ -445,36 +473,6 @@ class test_Env(ClassChecker): e = raises(StandardError, o.__lock__) assert str(e) == 'Env.__lock__() already called' - def test_getitem(self): - """ - Test the `ipalib.config.Env.__getitem__` method. - """ - o = self.cls() - value = 'some value' - o.key = value - assert o.key is value - assert o['key'] is value - for name in ('one', 'two'): - e = raises(KeyError, getitem, o, name) - assert str(e) == repr(name) - - - - def test_delattr(self): - """ - Test the `ipalib.config.Env.__delattr__` method. - - This also tests that ``__delitem__`` is not implemented. - """ - o = self.cls() - o.one = 1 - assert o.one == 1 - for key in ('one', 'two'): - e = raises(AttributeError, delattr, o, key) - assert str(e) == 'cannot del Env.%s' % key - e = raises(AttributeError, delitem, o, key) - assert str(e) == '__delitem__' - def test_contains(self): """ Test the `ipalib.config.Env.__contains__` method. -- cgit From fd43b39145382b96cd2e0d0da3d5dcbe0d3a4a2a Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 22 Dec 2008 23:09:35 -0700 Subject: Moved setting of run-time variables from Env.__init__() to Env._bootstrap() --- tests/test_ipalib/test_config.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 740ef6cf..8884697e 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -147,13 +147,9 @@ class test_Env(ClassChecker): Test the `ipalib.config.Env.__init__` method. """ (o, home) = self.new() - ipalib = path.dirname(path.abspath(config.__file__)) - assert o.ipalib == ipalib - assert o.site_packages == path.dirname(ipalib) - assert o.script == path.abspath(sys.argv[0]) - assert o.bin == path.dirname(path.abspath(sys.argv[0])) - assert o.home == home.path - assert o.dot_ipa == home.join('.ipa') + assert list(o) == [] + assert len(o) == 0 + assert o.__islocked__() is False def test_setattr(self): """ @@ -246,10 +242,14 @@ class test_Env(ClassChecker): """ # Test defaults created by _bootstrap(): (o, home) = self.new() - assert 'in_tree' not in o - assert 'context' not in o - assert 'conf' not in o o._bootstrap() + ipalib = path.dirname(path.abspath(config.__file__)) + assert o.ipalib == ipalib + assert o.site_packages == path.dirname(ipalib) + assert o.script == path.abspath(sys.argv[0]) + assert o.bin == path.dirname(path.abspath(sys.argv[0])) + assert o.home == home.path + assert o.dot_ipa == home.join('.ipa') assert o.in_tree is False assert o.context == 'default' assert o.conf == '/etc/ipa/default.conf' @@ -422,6 +422,7 @@ class test_Env(ClassChecker): no_exist = tmp.join('no_exist.conf') assert not path.exists(no_exist) o = self.cls() + o._bootstrap() keys = tuple(o) orig = dict((k, o[k]) for k in o) assert o._merge_config(no_exist) is None -- cgit From 16526142f36e81f4d8a767f339c559188485f756 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 23 Dec 2008 01:11:03 -0700 Subject: Finished Env class docstring; more organizational cleanup in Env and its unit tests --- tests/test_ipalib/test_config.py | 122 +++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 50 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 8884697e..acdcfaae 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -32,7 +32,6 @@ from ipalib.constants import TYPE_ERROR, OVERRIDE_ERROR, SET_ERROR, DEL_ERROR from ipalib import config, constants - # Valid environment variables in (key, raw, value) tuples: # key: the name of the environment variable # raw: the value being set (possibly a string repr) @@ -48,6 +47,7 @@ good_vars = ( ('false_repr', ' False ', False), ('none', None, None), ('none_repr', ' None ', None), + ('empty', '', None), # These verify that the implied conversion is case-sensitive: ('not_true', ' true ', 'true'), @@ -56,7 +56,6 @@ good_vars = ( ) - # Random base64-encoded data to simulate a misbehaving config file. config_bad = """ /9j/4AAQSkZJRgABAQEAlgCWAAD//gAIT2xpdmVy/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgx @@ -96,6 +95,7 @@ i1Jmt0+5dfuOLbANB2H6MjzNzc2zv5ji1g2+5/MYnbb+Yh+T0kubUY940UUbUWtRpJN8w1CfebkK WfUu+/mDOAGOjsRo0UkIo+pPl6Rckl7ehuR1INGAj9u0kW2nXvK45YlQp1odukaICSAjgSQWf//Z """ + # A config file that tries to override some standard vars: config_override = """ [global] @@ -108,6 +108,7 @@ key2 = var2 key3 = var3 """ + # A config file that tests the automatic type conversion config_good = """ [global] @@ -117,6 +118,7 @@ no = False number = 42 """ + # A default config file to make sure it does not overwrite the explicit one config_default = """ [global] @@ -133,24 +135,26 @@ class test_Env(ClassChecker): _cls = config.Env - def new(self): - """ - Set os.environ['HOME'] to a tempdir. - - Returns tuple with new Env instance and the TempHome instance. - """ - home = TempHome() - return (self.cls(), home) - def test_init(self): """ Test the `ipalib.config.Env.__init__` method. """ - (o, home) = self.new() + o = self.cls() assert list(o) == [] assert len(o) == 0 assert o.__islocked__() is False + def test_lock(self): + """ + Test the `ipalib.config.Env.__lock__` method. + """ + o = self.cls() + assert o._Env__locked is False + o.__lock__() + assert o._Env__locked is True + e = raises(StandardError, o.__lock__) + assert str(e) == 'Env.__lock__() already called' + def test_setattr(self): """ Test the `ipalib.config.Env.__setattr__` method. @@ -227,7 +231,60 @@ class test_Env(ClassChecker): e = raises(AttributeError, delitem, o, key) assert str(e) == '__delitem__' + def test_contains(self): + """ + Test the `ipalib.config.Env.__contains__` method. + """ + o = self.cls() + items = [ + ('one', 1), + ('two', 2), + ('three', 3), + ('four', 4), + ] + for (key, value) in items: + assert key not in o + o[key] = value + assert key in o + + def test_len(self): + """ + Test the `ipalib.config.Env.__len__` method. + """ + o = self.cls() + assert len(o) == 0 + for i in xrange(1, 11): + key = 'key%d' % i + value = 'value %d' % i + o[key] = value + assert o[key] is value + assert len(o) == i + + def test_iter(self): + """ + Test the `ipalib.config.Env.__iter__` method. + """ + o = self.cls() + default_keys = tuple(o) + keys = ('one', 'two', 'three', 'four', 'five') + for key in keys: + o[key] = 'the value' + assert list(o) == sorted(keys + default_keys) + + def new(self): + """ + Set os.environ['HOME'] to a tempdir. + + Returns tuple with new Env instance and the TempHome instance. This + helper method is used in testing the bootstrap related methods below. + """ + home = TempHome() + return (self.cls(), home) + def bootstrap(self, **overrides): + """ + Helper method used in testing bootstrap related methods below. + """ (o, home) = self.new() assert o._isdone('_bootstrap') is False o._bootstrap(**overrides) @@ -290,6 +347,9 @@ class test_Env(ClassChecker): assert o[key] == value def finalize_core(self, **defaults): + """ + Helper method used in testing `Env._finalize_core`. + """ (o, home) = self.new() assert o._isdone('_finalize_core') is False o._finalize_core(**defaults) @@ -462,41 +522,3 @@ class test_Env(ClassChecker): assert o.yes is True assert o.no is False assert o.number == 42 - - def test_lock(self): - """ - Test the `ipalib.config.Env.__lock__` method. - """ - o = self.cls() - assert o._Env__locked is False - o.__lock__() - assert o._Env__locked is True - e = raises(StandardError, o.__lock__) - assert str(e) == 'Env.__lock__() already called' - - def test_contains(self): - """ - Test the `ipalib.config.Env.__contains__` method. - """ - o = self.cls() - items = [ - ('one', 1), - ('two', 2), - ('three', 3), - ('four', 4), - ] - for (key, value) in items: - assert key not in o - o[key] = value - assert key in o - - def test_iter(self): - """ - Test the `ipalib.config.Env.__iter__` method. - """ - o = self.cls() - default_keys = tuple(o) - keys = ('one', 'two', 'three', 'four', 'five') - for key in keys: - o[key] = 'the value' - assert list(o) == sorted(keys + default_keys) -- cgit From e14fc84dfccbb06f775bbd5d3de864c7b879453f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 29 Dec 2008 21:23:34 -0700 Subject: Renamed Env._merge_config() to Env._merge_from_file() --- tests/test_ipalib/test_config.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index acdcfaae..388994f4 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -471,9 +471,9 @@ class test_Env(ClassChecker): assert key in o assert o[key] is value - def test_merge_config(self): + def test_merge_from_file(self): """ - Test the `ipalib.config.Env._merge_config` method. + Test the `ipalib.config.Env._merge_from_file` method. """ tmp = TempDir() assert callable(tmp.join) @@ -485,27 +485,27 @@ class test_Env(ClassChecker): o._bootstrap() keys = tuple(o) orig = dict((k, o[k]) for k in o) - assert o._merge_config(no_exist) is None + assert o._merge_from_file(no_exist) is None assert tuple(o) == keys # Test an empty config file empty = tmp.touch('empty.conf') assert path.isfile(empty) - assert o._merge_config(empty) is None + assert o._merge_from_file(empty) is None assert tuple(o) == keys # Test a mal-formed config file: bad = tmp.join('bad.conf') open(bad, 'w').write(config_bad) assert path.isfile(bad) - assert o._merge_config(bad) is None + assert o._merge_from_file(bad) is None assert tuple(o) == keys # Test a valid config file that tries to override override = tmp.join('override.conf') open(override, 'w').write(config_override) assert path.isfile(override) - assert o._merge_config(override) == (4, 6) + assert o._merge_from_file(override) == (4, 6) for (k, v) in orig.items(): assert o[k] is v assert list(o) == sorted(keys + ('key0', 'key1', 'key2', 'key3')) @@ -517,7 +517,7 @@ class test_Env(ClassChecker): good = tmp.join('good.conf') open(good, 'w').write(config_good) assert path.isfile(good) - assert o._merge_config(good) == (3, 3) + assert o._merge_from_file(good) == (3, 3) assert list(o) == sorted(keys + ('yes', 'no', 'number')) assert o.yes is True assert o.no is False -- cgit From 447c88a2bb9dd364f9c67a73bfce5000ac81d375 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 30 Dec 2008 00:45:48 -0700 Subject: Started moving some core classes and functions from plugable.py to new base.py module --- tests/test_ipalib/test_base.py | 116 +++++++++++++++++++++++++++++++++++++++ tests/test_ipalib/test_config.py | 21 ++++++- 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 tests/test_ipalib/test_base.py (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_base.py b/tests/test_ipalib/test_base.py new file mode 100644 index 00000000..9feac6ac --- /dev/null +++ b/tests/test_ipalib/test_base.py @@ -0,0 +1,116 @@ +# Authors: +# Jason Gerard DeRose +# +# 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.base` module. +""" + +from tests.util import ClassChecker, raises +from ipalib.constants import NAME_REGEX +from ipalib.constants import TYPE_ERROR, SET_ERROR, DEL_ERROR +from ipalib import base + + +class test_ReadOnly(ClassChecker): + """ + Test the `ipalib.base.ReadOnly` class + """ + _cls = base.ReadOnly + + def test_lock(self): + """ + Test the `ipalib.base.ReadOnly.__lock__` method. + """ + o = self.cls() + assert o._ReadOnly__locked is False + o.__lock__() + assert o._ReadOnly__locked is True + e = raises(AssertionError, o.__lock__) # Can only be locked once + assert str(e) == '__lock__() can only be called once' + assert o._ReadOnly__locked is True # This should still be True + + def test_islocked(self): + """ + Test the `ipalib.base.ReadOnly.__islocked__` method. + """ + o = self.cls() + assert o.__islocked__() is False + o.__lock__() + assert o.__islocked__() is True + + def test_setattr(self): + """ + Test the `ipalib.base.ReadOnly.__setattr__` method. + """ + o = self.cls() + o.attr1 = 'Hello, world!' + assert o.attr1 == 'Hello, world!' + o.__lock__() + for name in ('attr1', 'attr2'): + e = raises(AttributeError, setattr, o, name, 'whatever') + assert str(e) == SET_ERROR % ('ReadOnly', name, 'whatever') + assert o.attr1 == 'Hello, world!' + + def test_delattr(self): + """ + Test the `ipalib.base.ReadOnly.__delattr__` method. + """ + o = self.cls() + o.attr1 = 'Hello, world!' + o.attr2 = 'How are you?' + assert o.attr1 == 'Hello, world!' + assert o.attr2 == 'How are you?' + del o.attr1 + assert not hasattr(o, 'attr1') + o.__lock__() + e = raises(AttributeError, delattr, o, 'attr2') + assert str(e) == DEL_ERROR % ('ReadOnly', 'attr2') + assert o.attr2 == 'How are you?' + + +def test_check_name(): + """ + Test the `ipalib.base.check_name` function. + """ + f = base.check_name + okay = [ + 'user_add', + 'stuff2junk', + 'sixty9', + ] + nope = [ + '_user_add', + '__user_add', + 'user_add_', + 'user_add__', + '_user_add_', + '__user_add__', + '60nine', + ] + for name in okay: + assert name is f(name) + e = raises(TypeError, f, unicode(name)) + assert str(e) == TYPE_ERROR % ('name', str, unicode(name), unicode) + error = 'name must match %r; got %r' + for name in nope: + e = raises(ValueError, f, name) + assert str(e) == error % (NAME_REGEX, name) + for name in okay: + e = raises(ValueError, f, name.upper()) + assert str(e) == error % (NAME_REGEX, name.upper()) diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 388994f4..7c53efe2 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -21,7 +21,6 @@ Test the `ipalib.config` module. """ -import types import os from os import path import sys @@ -29,6 +28,7 @@ from tests.util import raises, setitem, delitem, ClassChecker from tests.util import getitem, setitem, delitem from tests.util import TempDir, TempHome from ipalib.constants import TYPE_ERROR, OVERRIDE_ERROR, SET_ERROR, DEL_ERROR +from ipalib.constants import NAME_REGEX, NAME_ERROR from ipalib import config, constants @@ -56,6 +56,13 @@ good_vars = ( ) +bad_names = ( + ('CamelCase', 'value'), + ('_leading_underscore', 'value'), + ('trailing_underscore_', 'value'), +) + + # Random base64-encoded data to simulate a misbehaving config file. config_bad = """ /9j/4AAQSkZJRgABAQEAlgCWAAD//gAIT2xpdmVy/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgx @@ -179,6 +186,12 @@ class test_Env(ClassChecker): e = raises(AttributeError, setattr, o, name, raw) assert str(e) == SET_ERROR % ('Env', name, raw) + # Test that name is tested with check_name(): + o = self.cls() + for (name, value) in bad_names: + e = raises(ValueError, setattr, o, name, value) + assert str(e) == NAME_ERROR % (NAME_REGEX, name) + def test_setitem(self): """ Test the `ipalib.config.Env.__setitem__` method. @@ -203,6 +216,12 @@ class test_Env(ClassChecker): e = raises(AttributeError, o.__setitem__, key, raw) assert str(e) == SET_ERROR % ('Env', key, raw) + # Test that name is tested with check_name(): + o = self.cls() + for (key, value) in bad_names: + e = raises(ValueError, o.__setitem__, key, value) + assert str(e) == NAME_ERROR % (NAME_REGEX, key) + def test_getitem(self): """ Test the `ipalib.config.Env.__getitem__` method. -- cgit From 11e165073eb3bd21d764fa1c4d71f1e6a52eae1b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 30 Dec 2008 03:11:45 -0700 Subject: Docstring cleanup in the Env bootstraping methods --- tests/test_ipalib/test_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 7c53efe2..6737b086 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -510,7 +510,7 @@ class test_Env(ClassChecker): # Test an empty config file empty = tmp.touch('empty.conf') assert path.isfile(empty) - assert o._merge_from_file(empty) is None + assert o._merge_from_file(empty) == (0, 0) assert tuple(o) == keys # Test a mal-formed config file: -- cgit From 03c9114958e428c5fe6b286df9eda3bd932dc9dc Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 30 Dec 2008 13:52:36 -0700 Subject: More docstring cleanup in ipalib.config --- tests/test_ipalib/test_base.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_base.py b/tests/test_ipalib/test_base.py index 9feac6ac..49d5f39d 100644 --- a/tests/test_ipalib/test_base.py +++ b/tests/test_ipalib/test_base.py @@ -22,7 +22,7 @@ Test the `ipalib.base` module. """ from tests.util import ClassChecker, raises -from ipalib.constants import NAME_REGEX +from ipalib.constants import NAME_REGEX, NAME_ERROR from ipalib.constants import TYPE_ERROR, SET_ERROR, DEL_ERROR from ipalib import base @@ -107,10 +107,9 @@ def test_check_name(): assert name is f(name) e = raises(TypeError, f, unicode(name)) assert str(e) == TYPE_ERROR % ('name', str, unicode(name), unicode) - error = 'name must match %r; got %r' for name in nope: e = raises(ValueError, f, name) - assert str(e) == error % (NAME_REGEX, name) + assert str(e) == NAME_ERROR % (NAME_REGEX, name) for name in okay: e = raises(ValueError, f, name.upper()) - assert str(e) == error % (NAME_REGEX, name.upper()) + assert str(e) == NAME_ERROR % (NAME_REGEX, name.upper()) -- cgit From bc2395724708abc80c7c13c5474cefcfb6f3579c Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 30 Dec 2008 14:38:05 -0700 Subject: Added unit test for Env._merge() --- tests/test_ipalib/test_config.py | 140 ++++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 52 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 6737b086..5daad037 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -290,6 +290,94 @@ class test_Env(ClassChecker): o[key] = 'the value' assert list(o) == sorted(keys + default_keys) + def test_merge(self): + """ + Test the `ipalib.config.Env._merge` method. + """ + group1 = ( + ('key1', 'value 1'), + ('key2', 'value 2'), + ('key3', 'value 3'), + ('key4', 'value 4'), + ) + group2 = ( + ('key0', 'Value 0'), + ('key2', 'Value 2'), + ('key4', 'Value 4'), + ('key5', 'Value 5'), + ) + o = self.cls() + assert o._merge(**dict(group1)) == (4, 4) + assert len(o) == 4 + assert list(o) == list(key for (key, value) in group1) + for (key, value) in group1: + assert getattr(o, key) is value + assert o[key] is value + assert o._merge(**dict(group2)) == (2, 4) + assert len(o) == 6 + expected = dict(group2) + expected.update(dict(group1)) + assert list(o) == sorted(expected) + assert expected['key2'] == 'value 2' # And not 'Value 2' + for (key, value) in expected.iteritems(): + assert getattr(o, key) is value + assert o[key] is value + assert o._merge(**expected) == (0, 6) + assert len(o) == 6 + assert list(o) == sorted(expected) + + def test_merge_from_file(self): + """ + Test the `ipalib.config.Env._merge_from_file` method. + """ + tmp = TempDir() + assert callable(tmp.join) + + # Test a config file that doesn't exist + no_exist = tmp.join('no_exist.conf') + assert not path.exists(no_exist) + o = self.cls() + o._bootstrap() + keys = tuple(o) + orig = dict((k, o[k]) for k in o) + assert o._merge_from_file(no_exist) is None + assert tuple(o) == keys + + # Test an empty config file + empty = tmp.touch('empty.conf') + assert path.isfile(empty) + assert o._merge_from_file(empty) == (0, 0) + assert tuple(o) == keys + + # Test a mal-formed config file: + bad = tmp.join('bad.conf') + open(bad, 'w').write(config_bad) + assert path.isfile(bad) + assert o._merge_from_file(bad) is None + assert tuple(o) == keys + + # Test a valid config file that tries to override + override = tmp.join('override.conf') + open(override, 'w').write(config_override) + assert path.isfile(override) + assert o._merge_from_file(override) == (4, 6) + for (k, v) in orig.items(): + assert o[k] is v + assert list(o) == sorted(keys + ('key0', 'key1', 'key2', 'key3')) + for i in xrange(4): + assert o['key%d' % i] == ('var%d' % i) + keys = tuple(o) + + # Test a valid config file with type conversion + good = tmp.join('good.conf') + open(good, 'w').write(config_good) + assert path.isfile(good) + assert o._merge_from_file(good) == (3, 3) + assert list(o) == sorted(keys + ('yes', 'no', 'number')) + assert o.yes is True + assert o.no is False + assert o.number == 42 + def new(self): """ Set os.environ['HOME'] to a tempdir. @@ -489,55 +577,3 @@ class test_Env(ClassChecker): o._finalize(**lastchance) assert key in o assert o[key] is value - - def test_merge_from_file(self): - """ - Test the `ipalib.config.Env._merge_from_file` method. - """ - tmp = TempDir() - assert callable(tmp.join) - - # Test a config file that doesn't exist - no_exist = tmp.join('no_exist.conf') - assert not path.exists(no_exist) - o = self.cls() - o._bootstrap() - keys = tuple(o) - orig = dict((k, o[k]) for k in o) - assert o._merge_from_file(no_exist) is None - assert tuple(o) == keys - - # Test an empty config file - empty = tmp.touch('empty.conf') - assert path.isfile(empty) - assert o._merge_from_file(empty) == (0, 0) - assert tuple(o) == keys - - # Test a mal-formed config file: - bad = tmp.join('bad.conf') - open(bad, 'w').write(config_bad) - assert path.isfile(bad) - assert o._merge_from_file(bad) is None - assert tuple(o) == keys - - # Test a valid config file that tries to override - override = tmp.join('override.conf') - open(override, 'w').write(config_override) - assert path.isfile(override) - assert o._merge_from_file(override) == (4, 6) - for (k, v) in orig.items(): - assert o[k] is v - assert list(o) == sorted(keys + ('key0', 'key1', 'key2', 'key3')) - for i in xrange(4): - assert o['key%d' % i] == ('var%d' % i) - keys = tuple(o) - - # Test a valid config file with type conversion - good = tmp.join('good.conf') - open(good, 'w').write(config_good) - assert path.isfile(good) - assert o._merge_from_file(good) == (3, 3) - assert list(o) == sorted(keys + ('yes', 'no', 'number')) - assert o.yes is True - assert o.no is False - assert o.number == 42 -- cgit From 379c549fc16fbb2eed6685f5e189da26f021abe9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 30 Dec 2008 15:02:15 -0700 Subject: Env now supports float values --- tests/test_ipalib/test_config.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index 5daad037..ab8d9006 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -1,5 +1,6 @@ # Authors: # Martin Nagy +# Jason Gerard DeRose # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty information @@ -41,6 +42,8 @@ good_vars = ( ('trailing_whitespace', ' value ', 'value'), ('an_int', 42, 42), ('int_repr', ' 42 ', 42), + ('a_float', 3.14, 3.14), + ('float_repr', ' 3.14 ', 3.14), ('true', True, True), ('true_repr', ' True ', True), ('false', False, False), @@ -120,9 +123,12 @@ key3 = var3 config_good = """ [global] +string = Hello world! +null = None yes = True no = False number = 42 +floating = 3.14 """ @@ -372,11 +378,15 @@ class test_Env(ClassChecker): good = tmp.join('good.conf') open(good, 'w').write(config_good) assert path.isfile(good) - assert o._merge_from_file(good) == (3, 3) - assert list(o) == sorted(keys + ('yes', 'no', 'number')) + assert o._merge_from_file(good) == (6, 6) + added = ('string', 'null', 'yes', 'no', 'number', 'floating') + assert list(o) == sorted(keys + added) + assert o.string == 'Hello world!' + assert o.null is None assert o.yes is True assert o.no is False assert o.number == 42 + assert o.floating == 3.14 def new(self): """ -- cgit From 57dae28d9c4eb90d49f98cd528f85d203c8cbc94 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 30 Dec 2008 21:14:51 -0700 Subject: Added base.lock() and base.islocked() functions; added corresponding unit tests --- tests/test_ipalib/test_base.py | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_base.py b/tests/test_ipalib/test_base.py index 49d5f39d..87e4c063 100644 --- a/tests/test_ipalib/test_base.py +++ b/tests/test_ipalib/test_base.py @@ -84,6 +84,79 @@ class test_ReadOnly(ClassChecker): assert o.attr2 == 'How are you?' +def test_lock(): + """ + Test the `ipalib.base.lock` function + """ + f = base.lock + + # Test with ReadOnly instance: + o = base.ReadOnly() + assert o.__islocked__() is False + assert f(o) is o + assert o.__islocked__() is True + e = raises(AssertionError, f, o) + assert str(e) == 'already locked: %r' % o + + # Test with another class implemented locking protocol: + class Lockable(object): + __locked = False + def __lock__(self): + self.__locked = True + def __islocked__(self): + return self.__locked + o = Lockable() + assert o.__islocked__() is False + assert f(o) is o + assert o.__islocked__() is True + e = raises(AssertionError, f, o) + assert str(e) == 'already locked: %r' % o + + # Test with a class incorrectly implementing the locking protocol: + class Broken(object): + def __lock__(self): + pass + def __islocked__(self): + return False + o = Broken() + e = raises(AssertionError, f, o) + assert str(e) == 'failed to lock: %r' % o + + +def test_islocked(): + """ + Test the `ipalib.base.islocked` function. + """ + f = base.islocked + + # Test with ReadOnly instance: + o = base.ReadOnly() + assert f(o) is False + o.__lock__() + assert f(o) is True + + # Test with another class implemented locking protocol: + class Lockable(object): + __locked = False + def __lock__(self): + self.__locked = True + def __islocked__(self): + return self.__locked + o = Lockable() + assert f(o) is False + o.__lock__() + assert f(o) is True + + # Test with a class incorrectly implementing the locking protocol: + class Broken(object): + __lock__ = False + def __islocked__(self): + return False + o = Broken() + e = raises(AssertionError, f, o) + assert str(e) == 'no __lock__() method: %r' % o + + def test_check_name(): """ Test the `ipalib.base.check_name` function. -- cgit From 86325bf4ebd8a9d40e81e4fd835635dfaa4139cd Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 31 Dec 2008 02:28:49 -0700 Subject: Copied plugable.NameSpace to base.NameSpace and made many docstring and unit test improvements --- tests/test_ipalib/test_base.py | 166 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_base.py b/tests/test_ipalib/test_base.py index 87e4c063..ce88f23f 100644 --- a/tests/test_ipalib/test_base.py +++ b/tests/test_ipalib/test_base.py @@ -23,7 +23,7 @@ Test the `ipalib.base` module. from tests.util import ClassChecker, raises from ipalib.constants import NAME_REGEX, NAME_ERROR -from ipalib.constants import TYPE_ERROR, SET_ERROR, DEL_ERROR +from ipalib.constants import TYPE_ERROR, SET_ERROR, DEL_ERROR, OVERRIDE_ERROR from ipalib import base @@ -186,3 +186,167 @@ def test_check_name(): for name in okay: e = raises(ValueError, f, name.upper()) assert str(e) == NAME_ERROR % (NAME_REGEX, name.upper()) + + +def membername(i): + return 'member%03d' % i + + +class DummyMember(object): + def __init__(self, i): + self.i = i + self.name = membername(i) + + +def gen_members(*indexes): + return tuple(DummyMember(i) for i in indexes) + + +class test_NameSpace(ClassChecker): + """ + Test the `ipalib.base.NameSpace` class. + """ + _cls = base.NameSpace + + def new(self, count, sort=True): + members = tuple(DummyMember(i) for i in xrange(count, 0, -1)) + assert len(members) == count + o = self.cls(members, sort=sort) + return (o, members) + + def test_init(self): + """ + Test the `ipalib.base.NameSpace.__init__` method. + """ + o = self.cls([]) + assert len(o) == 0 + assert list(o) == [] + assert list(o()) == [] + + # Test members as attribute and item: + for cnt in (3, 42): + for sort in (True, False): + (o, members) = self.new(cnt, sort=sort) + assert len(members) == cnt + for m in members: + assert getattr(o, m.name) is m + assert o[m.name] is m + + # Test that TypeError is raised if sort is not a bool: + e = raises(TypeError, self.cls, [], sort=None) + assert str(e) == TYPE_ERROR % ('sort', bool, None, type(None)) + + # Test that AttributeError is raised with duplicate member name: + members = gen_members(0, 1, 2, 1, 3) + e = raises(AttributeError, self.cls, members) + assert str(e) == OVERRIDE_ERROR % ( + 'NameSpace', membername(1), members[1], members[3] + ) + + def test_len(self): + """ + Test the `ipalib.base.NameSpace.__len__` method. + """ + for count in (5, 18, 127): + (o, members) = self.new(count) + assert len(o) == count + (o, members) = self.new(count, sort=False) + assert len(o) == count + + def test_iter(self): + """ + Test the `ipalib.base.NameSpace.__iter__` method. + """ + (o, members) = self.new(25) + assert list(o) == sorted(m.name for m in members) + (o, members) = self.new(25, sort=False) + assert list(o) == list(m.name for m in members) + + def test_call(self): + """ + Test the `ipalib.base.NameSpace.__call__` method. + """ + (o, members) = self.new(25) + assert list(o()) == sorted(members, key=lambda m: m.name) + (o, members) = self.new(25, sort=False) + assert tuple(o()) == members + + def test_contains(self): + """ + Test the `ipalib.base.NameSpace.__contains__` method. + """ + yes = (99, 3, 777) + no = (9, 333, 77) + for sort in (True, False): + members = gen_members(*yes) + o = self.cls(members, sort=sort) + for i in yes: + assert membername(i) in o + assert membername(i).upper() not in o + for i in no: + assert membername(i) not in o + + def test_getitem(self): + """ + Test the `ipalib.base.NameSpace.__getitem__` method. + """ + cnt = 17 + for sort in (True, False): + (o, members) = self.new(cnt, sort=sort) + assert len(members) == cnt + if sort is True: + members = tuple(sorted(members, key=lambda m: m.name)) + + # Test str keys: + for m in members: + assert o[m.name] is m + e = raises(KeyError, o.__getitem__, 'nope') + + # Test int indexes: + for i in xrange(cnt): + assert o[i] is members[i] + e = raises(IndexError, o.__getitem__, cnt) + + # Test negative int indexes: + for i in xrange(1, cnt + 1): + assert o[-i] is members[-i] + e = raises(IndexError, o.__getitem__, -(cnt + 1)) + + # Test slicing: + assert o[3:] == members[3:] + assert o[:10] == members[:10] + assert o[3:10] == members[3:10] + assert o[-9:] == members[-9:] + assert o[:-4] == members[:-4] + assert o[-9:-4] == members[-9:-4] + + # Test that TypeError is raised with wrong type + e = raises(TypeError, o.__getitem__, 3.0) + assert str(e) == TYPE_ERROR % ('key', (str, int, slice), 3.0, float) + + def test_repr(self): + """ + Test the `ipalib.base.NameSpace.__repr__` method. + """ + for cnt in (0, 1, 2): + for sort in (True, False): + (o, members) = self.new(cnt, sort=sort) + if cnt == 1: + assert repr(o) == \ + 'NameSpace(<%d member>, sort=%r)' % (cnt, sort) + else: + assert repr(o) == \ + 'NameSpace(<%d members>, sort=%r)' % (cnt, sort) + + def test_todict(self): + """ + Test the `ipalib.base.NameSpace.__todict__` method. + """ + for cnt in (3, 101): + for sort in (True, False): + (o, members) = self.new(cnt, sort=sort) + d = o.__todict__() + assert d == dict((m.name, m) for m in members) + + # Test that a copy is returned: + assert o.__todict__() is not d -- cgit From b4dc333ee2a010f3629002932d06a8b8a10df1d3 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 2 Jan 2009 00:46:45 -0700 Subject: Removed depreciated code in ipalib.plugable that has been moving into ipalib.base --- tests/test_ipalib/test_plugable.py | 191 ------------------------------------- 1 file changed, 191 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index b0594323..9eb102ff 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -28,100 +28,6 @@ from tests.util import ClassChecker, create_test_api from ipalib import plugable, errors -class test_ReadOnly(ClassChecker): - """ - Test the `ipalib.plugable.ReadOnly` class - """ - _cls = plugable.ReadOnly - - def test_class(self): - """ - Test the `ipalib.plugable.ReadOnly` class - """ - assert self.cls.__bases__ == (object,) - assert callable(self.cls.__lock__) - assert callable(self.cls.__islocked__) - - def test_lock(self): - """ - Test the `ipalib.plugable.ReadOnly.__lock__` method. - """ - o = self.cls() - assert o._ReadOnly__locked is False - o.__lock__() - assert o._ReadOnly__locked is True - e = raises(AssertionError, o.__lock__) # Can only be locked once - assert str(e) == '__lock__() can only be called once' - assert o._ReadOnly__locked is True # This should still be True - - def test_lock(self): - """ - Test the `ipalib.plugable.ReadOnly.__islocked__` method. - """ - o = self.cls() - assert o.__islocked__() is False - o.__lock__() - assert o.__islocked__() is True - - def test_setattr(self): - """ - Test the `ipalib.plugable.ReadOnly.__setattr__` method. - """ - o = self.cls() - o.attr1 = 'Hello, world!' - assert o.attr1 == 'Hello, world!' - o.__lock__() - for name in ('attr1', 'attr2'): - e = raises(AttributeError, setattr, o, name, 'whatever') - assert str(e) == 'read-only: cannot set ReadOnly.%s' % name - assert o.attr1 == 'Hello, world!' - - def test_delattr(self): - """ - Test the `ipalib.plugable.ReadOnly.__delattr__` method. - """ - o = self.cls() - o.attr1 = 'Hello, world!' - o.attr2 = 'How are you?' - assert o.attr1 == 'Hello, world!' - assert o.attr2 == 'How are you?' - del o.attr1 - assert not hasattr(o, 'attr1') - o.__lock__() - e = raises(AttributeError, delattr, o, 'attr2') - assert str(e) == 'read-only: cannot del ReadOnly.attr2' - assert o.attr2 == 'How are you?' - - -def test_lock(): - """ - Test the `ipalib.plugable.lock` function. - """ - f = plugable.lock - - # Test on a ReadOnly instance: - o = plugable.ReadOnly() - assert not o.__islocked__() - assert f(o) is o - assert o.__islocked__() - - # Test on something not subclassed from ReadOnly: - class not_subclass(object): - def __lock__(self): - pass - def __islocked__(self): - return True - o = not_subclass() - raises(ValueError, f, o) - - # Test that it checks __islocked__(): - class subclass(plugable.ReadOnly): - def __islocked__(self): - return False - o = subclass() - raises(AssertionError, f, o) - - class test_SetProxy(ClassChecker): """ Test the `ipalib.plugable.SetProxy` class. @@ -472,7 +378,6 @@ class test_Plugin(ClassChecker): assert e.argv == ('/bin/false',) - class test_PluginProxy(ClassChecker): """ Test the `ipalib.plugable.PluginProxy` class. @@ -595,102 +500,6 @@ class test_PluginProxy(ClassChecker): assert read_only(c, 'name') == 'another_name' -def test_check_name(): - """ - Test the `ipalib.plugable.check_name` function. - """ - f = plugable.check_name - okay = [ - 'user_add', - 'stuff2junk', - 'sixty9', - ] - nope = [ - '_user_add', - '__user_add', - 'user_add_', - 'user_add__', - '_user_add_', - '__user_add__', - '60nine', - ] - for name in okay: - assert name is f(name) - e = raises(TypeError, f, unicode(name)) - assert str(e) == errors.TYPE_FORMAT % ('name', str, unicode(name)) - for name in nope: - raises(errors.NameSpaceError, f, name) - for name in okay: - raises(errors.NameSpaceError, f, name.upper()) - -class DummyMember(object): - def __init__(self, i): - assert type(i) is int - self.name = 'member_%02d' % i - - -class test_NameSpace(ClassChecker): - """ - Test the `ipalib.plugable.NameSpace` class. - """ - _cls = plugable.NameSpace - - def test_class(self): - """ - Test the `ipalib.plugable.NameSpace` class. - """ - assert self.cls.__bases__ == (plugable.ReadOnly,) - - def test_init(self): - """ - Test the `ipalib.plugable.NameSpace.__init__` method. - """ - o = self.cls(tuple()) - assert list(o) == [] - assert list(o()) == [] - for cnt in (10, 25): - members = tuple(DummyMember(cnt - i) for i in xrange(cnt)) - for sort in (True, False): - o = self.cls(members, sort=sort) - if sort: - ordered = tuple(sorted(members, key=lambda m: m.name)) - else: - ordered = members - names = tuple(m.name for m in ordered) - assert o.__todict__() == dict((o.name, o) for o in ordered) - - # Test __len__: - assert len(o) == cnt - - # Test __contains__: - for name in names: - assert name in o - assert ('member_00') not in o - - # Test __iter__, __call__: - assert tuple(o) == names - assert tuple(o()) == ordered - - # Test __getitem__, getattr: - for (i, member) in enumerate(ordered): - assert o[i] is member - name = member.name - assert o[name] is member - assert read_only(o, name) is member - - # Test negative indexes: - for i in xrange(1, cnt + 1): - assert o[-i] is ordered[-i] - - # Test slices: - assert o[2:cnt-5] == ordered[2:cnt-5] - assert o[::3] == ordered[::3] - - # Test __repr__: - assert repr(o) == \ - 'NameSpace(<%d members>, sort=%r)' % (cnt, sort) - - def test_Registrar(): """ Test the `ipalib.plugable.Registrar` class -- cgit From 0d3ddef93b0a72b824297e5504e435a4427f14bd Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sat, 3 Jan 2009 02:35:36 -0700 Subject: Started fleshing out reoganization of errors in errors.py (with gettext support) --- tests/test_ipalib/test_error2.py | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/test_ipalib/test_error2.py (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_error2.py b/tests/test_ipalib/test_error2.py new file mode 100644 index 00000000..d70e49be --- /dev/null +++ b/tests/test_ipalib/test_error2.py @@ -0,0 +1,41 @@ +# Authors: +# Jason Gerard DeRose +# +# 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.error2` module. +""" + +import re +import inspect +from ipalib import errors2 + + +def test_public_errors(): + """ + Test the `ipalib.errors2.public_errors` module variable. + """ + for klass in errors2.public_errors: + assert issubclass(klass, errors2.PublicError) + assert not issubclass(klass, errors2.PrivateError) + assert type(klass.code) is int + assert 900 <= klass.code <= 5999 + doc = inspect.getdoc(klass) + m = re.match(r'^\*{2}(\d+)\*{2} ', doc) + assert m is not None, doc + assert int(m.group(1)) == klass.code, klass.__name__ -- cgit From d1517b95ca14773773647434fb589c8224307328 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sat, 3 Jan 2009 15:35:54 -0700 Subject: Ported errors.SubprocessError to errors2 --- tests/test_ipalib/test_error2.py | 79 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_error2.py b/tests/test_ipalib/test_error2.py index d70e49be..f8b1a314 100644 --- a/tests/test_ipalib/test_error2.py +++ b/tests/test_ipalib/test_error2.py @@ -26,11 +26,90 @@ import inspect from ipalib import errors2 +class PrivateExceptionTester(object): + _klass = None + __klass = None + + def __get_klass(self): + if self.__klass is None: + self.__klass = self._klass + assert issubclass(self.__klass, StandardError) + assert issubclass(self.__klass, errors2.PrivateError) + assert not issubclass(self.__klass, errors2.PublicError) + return self.__klass + klass = property(__get_klass) + + def new(self, **kw): + for (key, value) in kw.iteritems(): + assert not hasattr(self.klass, key), key + inst = self.klass(**kw) + assert isinstance(inst, StandardError) + assert isinstance(inst, errors2.PrivateError) + assert isinstance(inst, self.klass) + assert not isinstance(inst, errors2.PublicError) + for (key, value) in kw.iteritems(): + assert getattr(inst, key) is value + assert str(inst) == self.klass.format % kw + assert inst.message == str(inst) + return inst + + +class test_PrivateError(PrivateExceptionTester): + """ + Test the `ipalib.errors2.PrivateError` exception. + """ + _klass = errors2.PrivateError + + def test_init(self): + """ + Test the `ipalib.errors2.PrivateError.__init__` method. + """ + inst = self.klass(key1='Value 1', key2='Value 2') + assert inst.key1 == 'Value 1' + assert inst.key2 == 'Value 2' + assert str(inst) == '' + + # Test subclass and use of format: + class subclass(self.klass): + format = '%(true)r %(text)r %(number)r' + + kw = dict(true=True, text='Hello!', number=18) + inst = subclass(**kw) + assert inst.true is True + assert inst.text is kw['text'] + assert inst.number is kw['number'] + assert str(inst) == subclass.format % kw + + # Test via PrivateExceptionTester.new() + inst = self.new(**kw) + assert isinstance(inst, self.klass) + assert inst.true is True + assert inst.text is kw['text'] + assert inst.number is kw['number'] + + +class test_SubprocessError(PrivateExceptionTester): + """ + Test the `ipalib.errors2.SubprocessError` exception. + """ + _klass = errors2.SubprocessError + + def test_init(self): + """ + Test the `ipalib.errors2.SubprocessError.__init__` method. + """ + inst = self.klass(returncode=1, argv=('/bin/false',)) + assert inst.returncode == 1 + assert inst.argv == ('/bin/false',) + assert str(inst) == "return code 1 from ('/bin/false',)" + + def test_public_errors(): """ Test the `ipalib.errors2.public_errors` module variable. """ for klass in errors2.public_errors: + assert issubclass(klass, StandardError) assert issubclass(klass, errors2.PublicError) assert not issubclass(klass, errors2.PrivateError) assert type(klass.code) is int -- cgit From 6b6e6b1cab7a633faf16631a565ecb6988dadb48 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sat, 3 Jan 2009 17:27:53 -0700 Subject: Ported plugin registration errors into errors2.py; plugable.Registrar now raises new errors2 exceptions --- tests/test_ipalib/test_error2.py | 78 +++++++++++++++++++++++++++++++++++++- tests/test_ipalib/test_plugable.py | 22 ++++++++--- 2 files changed, 93 insertions(+), 7 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_error2.py b/tests/test_ipalib/test_error2.py index f8b1a314..9be24756 100644 --- a/tests/test_ipalib/test_error2.py +++ b/tests/test_ipalib/test_error2.py @@ -92,16 +92,92 @@ class test_SubprocessError(PrivateExceptionTester): """ Test the `ipalib.errors2.SubprocessError` exception. """ + _klass = errors2.SubprocessError def test_init(self): """ Test the `ipalib.errors2.SubprocessError.__init__` method. """ - inst = self.klass(returncode=1, argv=('/bin/false',)) + inst = self.new(returncode=1, argv=('/bin/false',)) assert inst.returncode == 1 assert inst.argv == ('/bin/false',) assert str(inst) == "return code 1 from ('/bin/false',)" + assert inst.message == str(inst) + + +class test_PluginSubclassError(PrivateExceptionTester): + """ + Test the `ipalib.errors2.PluginSubclassError` exception. + """ + + _klass = errors2.PluginSubclassError + + def test_init(self): + """ + Test the `ipalib.errors2.PluginSubclassError.__init__` method. + """ + inst = self.new(plugin='bad', bases=('base1', 'base2')) + assert inst.plugin == 'bad' + assert inst.bases == ('base1', 'base2') + assert str(inst) == \ + "'bad' not subclass of any base in ('base1', 'base2')" + assert inst.message == str(inst) + + +class test_PluginDuplicateError(PrivateExceptionTester): + """ + Test the `ipalib.errors2.PluginDuplicateError` exception. + """ + + _klass = errors2.PluginDuplicateError + + def test_init(self): + """ + Test the `ipalib.errors2.PluginDuplicateError.__init__` method. + """ + inst = self.new(plugin='my_plugin') + assert inst.plugin == 'my_plugin' + assert str(inst) == "'my_plugin' was already registered" + assert inst.message == str(inst) + + +class test_PluginOverrideError(PrivateExceptionTester): + """ + Test the `ipalib.errors2.PluginOverrideError` exception. + """ + + _klass = errors2.PluginOverrideError + + def test_init(self): + """ + Test the `ipalib.errors2.PluginOverrideError.__init__` method. + """ + inst = self.new(base='Base', name='cmd', plugin='my_cmd') + assert inst.base == 'Base' + assert inst.name == 'cmd' + assert inst.plugin == 'my_cmd' + assert str(inst) == "unexpected override of Base.cmd with 'my_cmd'" + assert inst.message == str(inst) + + +class test_PluginMissingOverrideError(PrivateExceptionTester): + """ + Test the `ipalib.errors2.PluginMissingOverrideError` exception. + """ + + _klass = errors2.PluginMissingOverrideError + + def test_init(self): + """ + Test the `ipalib.errors2.PluginMissingOverrideError.__init__` method. + """ + inst = self.new(base='Base', name='cmd', plugin='my_cmd') + assert inst.base == 'Base' + assert inst.name == 'cmd' + assert inst.plugin == 'my_cmd' + assert str(inst) == "Base.cmd not registered, cannot override with 'my_cmd'" + assert inst.message == str(inst) def test_public_errors(): diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 9eb102ff..dbf0cc3f 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -25,7 +25,7 @@ import inspect from tests.util import raises, no_set, no_del, read_only from tests.util import getitem, setitem, delitem from tests.util import ClassChecker, create_test_api -from ipalib import plugable, errors +from ipalib import plugable, errors, errors2 class test_SetProxy(ClassChecker): @@ -534,11 +534,14 @@ def test_Registrar(): # Check that TypeError is raised trying to register something that isn't # a class: - raises(TypeError, r, plugin1()) + p = plugin1() + e = raises(TypeError, r, p) + assert str(e) == 'plugin must be a class; got %r' % p # Check that SubclassError is raised trying to register a class that is # not a subclass of an allowed base: - raises(errors.SubclassError, r, plugin3) + e = raises(errors2.PluginSubclassError, r, plugin3) + assert e.plugin is plugin3 # Check that registration works r(plugin1) @@ -548,7 +551,8 @@ def test_Registrar(): # Check that DuplicateError is raised trying to register exact class # again: - raises(errors.DuplicateError, r, plugin1) + e = raises(errors2.PluginDuplicateError, r, plugin1) + assert e.plugin is plugin1 # Check that OverrideError is raised trying to register class with same # name and same base: @@ -557,7 +561,10 @@ def test_Registrar(): pass class plugin1(base1_extended): pass - raises(errors.OverrideError, r, plugin1) + e = raises(errors2.PluginOverrideError, r, plugin1) + assert e.base == 'Base1' + assert e.name == 'plugin1' + assert e.plugin is plugin1 # Check that overriding works r(plugin1, override=True) @@ -567,7 +574,10 @@ def test_Registrar(): # Check that MissingOverrideError is raised trying to override a name # not yet registerd: - raises(errors.MissingOverrideError, r, plugin2, override=True) + e = raises(errors2.PluginMissingOverrideError, r, plugin2, override=True) + assert e.base == 'Base2' + assert e.name == 'plugin2' + assert e.plugin is plugin2 # Test that another plugin can be registered: assert len(r.Base2) == 0 -- cgit From bb6e9cfe9ff25f3a018b23785f71302911eab435 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sat, 3 Jan 2009 18:02:58 -0700 Subject: Plugin.call() now uses errors2 version of SubprocessError --- tests/test_ipalib/test_plugable.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index dbf0cc3f..c6c84fa1 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -372,8 +372,7 @@ class test_Plugin(ClassChecker): """ o = self.cls() o.call('/bin/true') is None - e = raises(errors.SubprocessError, o.call, '/bin/false') - assert str(e) == 'return code %d from %r' % (1, ('/bin/false',)) + e = raises(errors2.SubprocessError, o.call, '/bin/false') assert e.returncode == 1 assert e.argv == ('/bin/false',) -- cgit From c081ce5460018634fb30249ead2168ebf3a79044 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sat, 3 Jan 2009 22:03:37 -0700 Subject: request.create_translation() now sets context.ugettext and context.ungettext --- tests/test_ipalib/test_request.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_request.py b/tests/test_ipalib/test_request.py index 5efc0abd..7096b927 100644 --- a/tests/test_ipalib/test_request.py +++ b/tests/test_ipalib/test_request.py @@ -65,9 +65,9 @@ def test_create_translation(): c = request.context t = TempDir() - # Test that StandardError is raised if gettext or ngettext: - assert not (hasattr(c, 'gettext') or hasattr(c, 'ngettext')) - for name in 'gettext', 'ngettext': + # Test that StandardError is raised if ugettext or ungettext: + assert not (hasattr(c, 'ugettext') or hasattr(c, 'ungettext')) + for name in ('ugettext', 'ungettext'): setattr(c, name, None) e = raises(StandardError, f, 'ipa', None) assert str(e) == ( @@ -77,23 +77,23 @@ def test_create_translation(): delattr(c, name) # Test using default language: - assert not hasattr(c, 'gettext') - assert not hasattr(c, 'ngettext') + assert not hasattr(c, 'ugettext') + assert not hasattr(c, 'ungettext') assert not hasattr(c, 'languages') f('ipa', t.path) - assert hasattr(c, 'gettext') - assert hasattr(c, 'ngettext') + assert hasattr(c, 'ugettext') + assert hasattr(c, 'ungettext') assert c.languages == locale.getdefaultlocale()[:1] - del c.gettext - del c.ngettext + del c.ugettext + del c.ungettext del c.languages # Test using explicit languages: langs = ('de', 'es') f('ipa', t.path, *langs) - assert hasattr(c, 'gettext') - assert hasattr(c, 'ngettext') + assert hasattr(c, 'ugettext') + assert hasattr(c, 'ungettext') assert c.languages == langs - del c.gettext - del c.ngettext + del c.ugettext + del c.ungettext del c.languages -- cgit From c161784973fdedb146a4087d8692b157214c4db0 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 4 Jan 2009 00:46:21 -0700 Subject: Added request.ugettext() and request.ungettext() functions; added corresponding unit tests --- tests/test_ipalib/test_request.py | 68 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_request.py b/tests/test_ipalib/test_request.py index 7096b927..62afb140 100644 --- a/tests/test_ipalib/test_request.py +++ b/tests/test_ipalib/test_request.py @@ -23,11 +23,77 @@ Test the `ipalib.request` module. import threading import locale -from tests.util import raises, TempDir +from tests.util import raises, TempDir, DummyUGettext, DummyUNGettext from ipalib.constants import OVERRIDE_ERROR from ipalib import request +def assert_equal(val1, val2): + assert type(val1) is type(val2), '%r != %r' % (val1, val2) + assert val1 == val2, '%r != %r' % (val1, val2) + + +def test_ugettext(): + """ + Test the `ipalib.request.ugettext` function. + """ + f = request.ugettext + context = request.context + message = 'Hello, world!' + + # Test with no context.ugettext: + assert not hasattr(context, 'ugettext') + assert_equal(f(message), u'Hello, world!') + + # Test with dummy context.ugettext: + assert not hasattr(context, 'ugettext') + dummy = DummyUGettext() + context.ugettext = dummy + assert f(message) is dummy.translation + assert dummy.message is message + + # Cleanup + del context.ugettext + assert not hasattr(context, 'ugettext') + + +def test_ungettext(): + """ + Test the `ipalib.request.ungettext` function. + """ + f = request.ungettext + context = request.context + singular = 'Goose' + plural = 'Geese' + + # Test with no context.ungettext: + assert not hasattr(context, 'ungettext') + assert_equal(f(singular, plural, 1), u'Goose') + assert_equal(f(singular, plural, 2), u'Geese') + + # Test singular with dummy context.ungettext + assert not hasattr(context, 'ungettext') + dummy = DummyUNGettext() + context.ungettext = dummy + assert f(singular, plural, 1) is dummy.translation_singular + assert dummy.singular is singular + assert dummy.plural is plural + assert dummy.n == 1 + del context.ungettext + assert not hasattr(context, 'ungettext') + + # Test plural with dummy context.ungettext + assert not hasattr(context, 'ungettext') + dummy = DummyUNGettext() + context.ungettext = dummy + assert f(singular, plural, 2) is dummy.translation_plural + assert dummy.singular is singular + assert dummy.plural is plural + assert dummy.n == 2 + del context.ungettext + assert not hasattr(context, 'ungettext') + + def test_set_languages(): """ Test the `ipalib.request.set_languages` function. -- cgit From 2608838ef1f96b0c8d3ff3ed4310eaa63ba73031 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 4 Jan 2009 03:52:08 -0700 Subject: Quite a bit of work on new public errors and their unit tests --- tests/test_ipalib/test_error2.py | 84 ++++++++++++++++++++++++++++++++++++++- tests/test_ipalib/test_request.py | 8 +--- 2 files changed, 84 insertions(+), 8 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_error2.py b/tests/test_ipalib/test_error2.py index 9be24756..a5b1e7c5 100644 --- a/tests/test_ipalib/test_error2.py +++ b/tests/test_ipalib/test_error2.py @@ -23,7 +23,9 @@ Test the `ipalib.error2` module. import re import inspect +from tests.util import assert_equal, raises, DummyUGettext from ipalib import errors2 +from ipalib.constants import TYPE_ERROR class PrivateExceptionTester(object): @@ -180,6 +182,80 @@ class test_PluginMissingOverrideError(PrivateExceptionTester): assert inst.message == str(inst) + +############################################################################## +# Unit tests for public errors: + +class PublicExceptionTester(object): + _klass = None + __klass = None + + def __get_klass(self): + if self.__klass is None: + self.__klass = self._klass + assert issubclass(self.__klass, StandardError) + assert issubclass(self.__klass, errors2.PublicError) + assert not issubclass(self.__klass, errors2.PrivateError) + assert type(self.__klass.code) is int + assert 900 <= self.__klass.code <= 5999 + return self.__klass + klass = property(__get_klass) + + def new(self, message=None, **kw): + # Test that TypeError is raised if message isn't unicode: + e = raises(TypeError, self.klass, 'The message') + assert str(e) == TYPE_ERROR % ('message', unicode, 'The message', str) + + # Test the instance: + for (key, value) in kw.iteritems(): + assert not hasattr(self.klass, key), key + inst = self.klass(message=message, **kw) + assert isinstance(inst, StandardError) + assert isinstance(inst, errors2.PublicError) + assert isinstance(inst, self.klass) + assert not isinstance(inst, errors2.PrivateError) + for (key, value) in kw.iteritems(): + assert getattr(inst, key) is value + assert str(inst) == inst.get_format(lambda m: m) % kw + assert inst.message == str(inst) + return inst + + +class test_PublicError(PublicExceptionTester): + """ + Test the `ipalib.errors2.PublicError` exception. + """ + _klass = errors2.PublicError + + def test_init(self): + """ + Test the `ipalib.errors2.PublicError.__init__` method. + """ + inst = self.klass(key1='Value 1', key2='Value 2') + assert inst.key1 == 'Value 1' + assert inst.key2 == 'Value 2' + assert str(inst) == '' + + # Test subclass and use of message, get_format(): + class subclass(self.klass): + def get_format(self, _): + return _('%(true)r %(text)r %(number)r') + + kw = dict(true=True, text='Hello!', number=18) + inst = subclass(**kw) + assert inst.true is True + assert inst.text is kw['text'] + assert inst.number is kw['number'] + assert_equal(inst.message, u'%(true)r %(text)r %(number)r' % kw) + + # Test via PublicExceptionTester.new() + inst = self.new(**kw) + assert isinstance(inst, self.klass) + assert inst.true is True + assert inst.text is kw['text'] + assert inst.number is kw['number'] + + def test_public_errors(): """ Test the `ipalib.errors2.public_errors` module variable. @@ -191,6 +267,10 @@ def test_public_errors(): assert type(klass.code) is int assert 900 <= klass.code <= 5999 doc = inspect.getdoc(klass) + assert doc is not None, 'need class docstring for %s' % klass.__name__ m = re.match(r'^\*{2}(\d+)\*{2} ', doc) - assert m is not None, doc - assert int(m.group(1)) == klass.code, klass.__name__ + assert m is not None, "need '**CODE**' in %s docstring" % klass.__name__ + code = int(m.group(1)) + assert code == klass.code, ( + 'docstring=%r but code=%r in %s' % (code, klass.code, klass.__name__) + ) diff --git a/tests/test_ipalib/test_request.py b/tests/test_ipalib/test_request.py index 62afb140..819f2755 100644 --- a/tests/test_ipalib/test_request.py +++ b/tests/test_ipalib/test_request.py @@ -23,16 +23,12 @@ Test the `ipalib.request` module. import threading import locale -from tests.util import raises, TempDir, DummyUGettext, DummyUNGettext +from tests.util import raises, assert_equal +from tests.util import TempDir, DummyUGettext, DummyUNGettext from ipalib.constants import OVERRIDE_ERROR from ipalib import request -def assert_equal(val1, val2): - assert type(val1) is type(val2), '%r != %r' % (val1, val2) - assert val1 == val2, '%r != %r' % (val1, val2) - - def test_ugettext(): """ Test the `ipalib.request.ugettext` function. -- cgit From c121d0064bb7a7bd1a289ae29ceb2dee314c2d2f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 5 Jan 2009 01:20:14 -0700 Subject: New Param: Added Param.get_label() method for a way to retrieve translated message at request time --- tests/test_ipalib/test_error2.py | 2 +- tests/test_ipalib/test_parameter.py | 49 +++++++++++++++++++++++++++++++++++-- tests/test_ipalib/test_request.py | 8 +++--- 3 files changed, 52 insertions(+), 7 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_error2.py b/tests/test_ipalib/test_error2.py index a5b1e7c5..33f571eb 100644 --- a/tests/test_ipalib/test_error2.py +++ b/tests/test_ipalib/test_error2.py @@ -23,7 +23,7 @@ Test the `ipalib.error2` module. import re import inspect -from tests.util import assert_equal, raises, DummyUGettext +from tests.util import assert_equal, raises, dummy_ugettext from ipalib import errors2 from ipalib.constants import TYPE_ERROR diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index ef248b70..63a1f4ae 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -17,14 +17,14 @@ # 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 +from ipalib import parameter, request from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR, NULLS @@ -137,6 +137,7 @@ class test_Param(ClassChecker): # 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 @@ -200,6 +201,50 @@ class test_Param(ClassChecker): 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. diff --git a/tests/test_ipalib/test_request.py b/tests/test_ipalib/test_request.py index 819f2755..f26c270a 100644 --- a/tests/test_ipalib/test_request.py +++ b/tests/test_ipalib/test_request.py @@ -24,7 +24,7 @@ Test the `ipalib.request` module. import threading import locale from tests.util import raises, assert_equal -from tests.util import TempDir, DummyUGettext, DummyUNGettext +from tests.util import TempDir, dummy_ugettext, dummy_ungettext from ipalib.constants import OVERRIDE_ERROR from ipalib import request @@ -43,7 +43,7 @@ def test_ugettext(): # Test with dummy context.ugettext: assert not hasattr(context, 'ugettext') - dummy = DummyUGettext() + dummy = dummy_ugettext() context.ugettext = dummy assert f(message) is dummy.translation assert dummy.message is message @@ -69,7 +69,7 @@ def test_ungettext(): # Test singular with dummy context.ungettext assert not hasattr(context, 'ungettext') - dummy = DummyUNGettext() + dummy = dummy_ungettext() context.ungettext = dummy assert f(singular, plural, 1) is dummy.translation_singular assert dummy.singular is singular @@ -80,7 +80,7 @@ def test_ungettext(): # Test plural with dummy context.ungettext assert not hasattr(context, 'ungettext') - dummy = DummyUNGettext() + dummy = dummy_ungettext() context.ungettext = dummy assert f(singular, plural, 2) is dummy.translation_plural assert dummy.singular is singular -- cgit From 6d6c0d81ddbfc56672f0595a5f631c5e846d8b2b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 5 Jan 2009 02:20:09 -0700 Subject: New Param: decided on calling signature for rules; added unit tests for Bytes._rule_minlength, _rule_maxlength, and _rule_length --- tests/test_ipalib/test_parameter.py | 102 ++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 63a1f4ae..59e32031 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -346,6 +346,108 @@ class test_Bytes(ClassChecker): 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_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): """ -- cgit From 690ad4766d9265026d46fcc50118f341776f81b0 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 5 Jan 2009 02:45:07 -0700 Subject: New Param: added Str length rule methods; added corresponding unit tests --- tests/test_ipalib/test_parameter.py | 102 +++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 25 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 59e32031..e2016f06 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -396,31 +396,6 @@ class test_Bytes(ClassChecker): assert dummy.message == \ '%(name)s can be at most %(maxlength)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. @@ -477,3 +452,80 @@ class test_Str(ClassChecker): 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) -- cgit From 9e430755a5cbcd27e2312d5bee1061704a7215bf Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 6 Jan 2009 13:33:22 -0700 Subject: Renamed PublicError.code attribute to PublicError.errno --- tests/test_ipalib/test_error2.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_error2.py b/tests/test_ipalib/test_error2.py index 33f571eb..85bb0c2b 100644 --- a/tests/test_ipalib/test_error2.py +++ b/tests/test_ipalib/test_error2.py @@ -196,8 +196,8 @@ class PublicExceptionTester(object): assert issubclass(self.__klass, StandardError) assert issubclass(self.__klass, errors2.PublicError) assert not issubclass(self.__klass, errors2.PrivateError) - assert type(self.__klass.code) is int - assert 900 <= self.__klass.code <= 5999 + assert type(self.__klass.errno) is int + assert 900 <= self.__klass.errno <= 5999 return self.__klass klass = property(__get_klass) @@ -264,13 +264,13 @@ def test_public_errors(): assert issubclass(klass, StandardError) assert issubclass(klass, errors2.PublicError) assert not issubclass(klass, errors2.PrivateError) - assert type(klass.code) is int - assert 900 <= klass.code <= 5999 + assert type(klass.errno) is int + assert 900 <= klass.errno <= 5999 doc = inspect.getdoc(klass) assert doc is not None, 'need class docstring for %s' % klass.__name__ m = re.match(r'^\*{2}(\d+)\*{2} ', doc) - assert m is not None, "need '**CODE**' in %s docstring" % klass.__name__ - code = int(m.group(1)) - assert code == klass.code, ( - 'docstring=%r but code=%r in %s' % (code, klass.code, klass.__name__) + assert m is not None, "need '**ERRNO**' in %s docstring" % klass.__name__ + errno = int(m.group(1)) + assert errno == klass.errno, ( + 'docstring=%r but errno=%r in %s' % (errno, klass.errno, klass.__name__) ) -- cgit From 166b3ca80c2ed651eb2a5c20bcda5b51ed9e5e2e Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 6 Jan 2009 18:21:46 -0700 Subject: Added unit test for Env.__islocked__(); unit test for Env.__lock__() now also tests with base.lock() function --- tests/test_ipalib/test_config.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_config.py b/tests/test_ipalib/test_config.py index ab8d9006..d3109f7b 100644 --- a/tests/test_ipalib/test_config.py +++ b/tests/test_ipalib/test_config.py @@ -30,7 +30,7 @@ from tests.util import getitem, setitem, delitem from tests.util import TempDir, TempHome from ipalib.constants import TYPE_ERROR, OVERRIDE_ERROR, SET_ERROR, DEL_ERROR from ipalib.constants import NAME_REGEX, NAME_ERROR -from ipalib import config, constants +from ipalib import config, constants, base # Valid environment variables in (key, raw, value) tuples: @@ -162,12 +162,31 @@ class test_Env(ClassChecker): Test the `ipalib.config.Env.__lock__` method. """ o = self.cls() - assert o._Env__locked is False + assert o.__islocked__() is False o.__lock__() - assert o._Env__locked is True + assert o.__islocked__() is True e = raises(StandardError, o.__lock__) assert str(e) == 'Env.__lock__() already called' + # Also test with base.lock() function: + o = self.cls() + assert o.__islocked__() is False + assert base.lock(o) is o + assert o.__islocked__() is True + e = raises(AssertionError, base.lock, o) + assert str(e) == 'already locked: %r' % o + + def test_islocked(self): + """ + Test the `ipalib.config.Env.__islocked__` method. + """ + o = self.cls() + assert o.__islocked__() is False + assert base.islocked(o) is False + o.__lock__() + assert o.__islocked__() is True + assert base.islocked(o) is True + def test_setattr(self): """ Test the `ipalib.config.Env.__setattr__` method. -- cgit From 3e9eb0bda000ef138ff04c677aa9014186f547d3 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 8 Jan 2009 00:07:18 -0700 Subject: Changed PublicError so str(e) is untranslated (for logging) and added format=None kwarg for generic use --- tests/test_ipalib/test_error2.py | 129 +++++++++++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 17 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_error2.py b/tests/test_ipalib/test_error2.py index 85bb0c2b..cd13ba77 100644 --- a/tests/test_ipalib/test_error2.py +++ b/tests/test_ipalib/test_error2.py @@ -24,7 +24,7 @@ Test the `ipalib.error2` module. import re import inspect from tests.util import assert_equal, raises, dummy_ugettext -from ipalib import errors2 +from ipalib import errors2, request from ipalib.constants import TYPE_ERROR @@ -201,23 +201,21 @@ class PublicExceptionTester(object): return self.__klass klass = property(__get_klass) - def new(self, message=None, **kw): + def new(self, format=None, message=None, **kw): # Test that TypeError is raised if message isn't unicode: - e = raises(TypeError, self.klass, 'The message') + e = raises(TypeError, self.klass, message='The message') assert str(e) == TYPE_ERROR % ('message', unicode, 'The message', str) # Test the instance: for (key, value) in kw.iteritems(): assert not hasattr(self.klass, key), key - inst = self.klass(message=message, **kw) + inst = self.klass(format=format, message=message, **kw) assert isinstance(inst, StandardError) assert isinstance(inst, errors2.PublicError) assert isinstance(inst, self.klass) assert not isinstance(inst, errors2.PrivateError) for (key, value) in kw.iteritems(): assert getattr(inst, key) is value - assert str(inst) == inst.get_format(lambda m: m) % kw - assert inst.message == str(inst) return inst @@ -231,35 +229,127 @@ class test_PublicError(PublicExceptionTester): """ Test the `ipalib.errors2.PublicError.__init__` method. """ - inst = self.klass(key1='Value 1', key2='Value 2') - assert inst.key1 == 'Value 1' - assert inst.key2 == 'Value 2' - assert str(inst) == '' + context = request.context + message = u'The translated, interpolated message' + format = 'key=%(key1)r and key2=%(key2)r' + uformat = u'Translated key=%(key1)r and key2=%(key2)r' + val1 = 'Value 1' + val2 = 'Value 2' + kw = dict(key1=val1, key2=val2) + + assert not hasattr(context, 'ugettext') + + # Test with format=str, message=None + dummy = dummy_ugettext(uformat) + context.ugettext = dummy + inst = self.klass(format, **kw) + assert dummy.message is format # Means ugettext() called + assert inst.format is format + assert_equal(inst.message, format % kw) + assert_equal(inst.strerror, uformat % kw) + assert inst.forwarded is False + assert inst.key1 is val1 + assert inst.key2 is val2 + + # Test with format=None, message=unicode + dummy = dummy_ugettext(uformat) + context.ugettext = dummy + inst = self.klass(message=message, **kw) + assert not hasattr(dummy, 'message') # Means ugettext() not called + assert inst.format is None + assert inst.message is message + assert inst.strerror is message + assert inst.forwarded is True + assert inst.key1 is val1 + assert inst.key2 is val2 + + # Test with format=None, message=str + e = raises(TypeError, self.klass, message='the message', **kw) + assert str(e) == TYPE_ERROR % ('message', unicode, 'the message', str) + + # Test with format=None, message=None + e = raises(ValueError, self.klass, **kw) + assert str(e) == \ + 'PublicError.format is None yet format=None, message=None' + + + ###################################### + # Test via PublicExceptionTester.new() - # Test subclass and use of message, get_format(): + # Test with format=str, message=None + dummy = dummy_ugettext(uformat) + context.ugettext = dummy + inst = self.new(format, **kw) + assert isinstance(inst, self.klass) + assert dummy.message is format # Means ugettext() called + assert inst.format is format + assert_equal(inst.message, format % kw) + assert_equal(inst.strerror, uformat % kw) + assert inst.forwarded is False + assert inst.key1 is val1 + assert inst.key2 is val2 + + # Test with format=None, message=unicode + dummy = dummy_ugettext(uformat) + context.ugettext = dummy + inst = self.new(message=message, **kw) + assert isinstance(inst, self.klass) + assert not hasattr(dummy, 'message') # Means ugettext() not called + assert inst.format is None + assert inst.message is message + assert inst.strerror is message + assert inst.forwarded is True + assert inst.key1 is val1 + assert inst.key2 is val2 + + + ################## + # Test a subclass: class subclass(self.klass): - def get_format(self, _): - return _('%(true)r %(text)r %(number)r') + format = '%(true)r %(text)r %(number)r' + uformat = u'Translated %(true)r %(text)r %(number)r' kw = dict(true=True, text='Hello!', number=18) + + dummy = dummy_ugettext(uformat) + context.ugettext = dummy + + # Test with format=str, message=None + e = raises(ValueError, subclass, format, **kw) + assert str(e) == 'non-generic %r needs format=None; got format=%r' % ( + 'subclass', format) + + # Test with format=None, message=None: inst = subclass(**kw) + assert dummy.message is subclass.format # Means ugettext() called + assert inst.format is subclass.format + assert_equal(inst.message, subclass.format % kw) + assert_equal(inst.strerror, uformat % kw) + assert inst.forwarded is False assert inst.true is True assert inst.text is kw['text'] assert inst.number is kw['number'] - assert_equal(inst.message, u'%(true)r %(text)r %(number)r' % kw) - # Test via PublicExceptionTester.new() - inst = self.new(**kw) - assert isinstance(inst, self.klass) + # Test with format=None, message=unicode: + dummy = dummy_ugettext(uformat) + context.ugettext = dummy + inst = subclass(message=message, **kw) + assert not hasattr(dummy, 'message') # Means ugettext() not called + assert inst.format is subclass.format + assert inst.message is message + assert inst.strerror is message + assert inst.forwarded is True assert inst.true is True assert inst.text is kw['text'] assert inst.number is kw['number'] + del context.ugettext def test_public_errors(): """ Test the `ipalib.errors2.public_errors` module variable. """ + i = 0 for klass in errors2.public_errors: assert issubclass(klass, StandardError) assert issubclass(klass, errors2.PublicError) @@ -274,3 +364,8 @@ def test_public_errors(): assert errno == klass.errno, ( 'docstring=%r but errno=%r in %s' % (errno, klass.errno, klass.__name__) ) + + # Test format + if klass.format is not None: + assert klass.format is errors2.__messages[i] + i += 1 -- cgit From 5c7c0b35bb2484efad2a8776b42fbf4066618706 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 12 Jan 2009 16:14:46 -0700 Subject: New Param: added Param.validate() and Param._validate_scalar() methods; added corresponding unit tests --- tests/test_ipalib/test_parameter.py | 142 +++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index e2016f06..b379379c 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -21,10 +21,11 @@ Test the `ipalib.parameter` module. """ +from types import NoneType 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 import parameter, request, errors2 from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR, NULLS @@ -113,6 +114,20 @@ def test_parse_param_spec(): 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.parameter.Param` class. @@ -145,6 +160,7 @@ class test_Param(ClassChecker): assert o.normalizer is None assert o.default is None assert o.default_from is None + assert o.create_default is None assert o.flags == frozenset() # Test that ValueError is raised when a kwarg from a subclass @@ -287,6 +303,130 @@ class test_Param(ClassChecker): e = raises(NotImplementedError, o._convert_scalar, 'some value') assert str(e) == 'Subclass._convert_scalar()' + def test_validate(self): + """ + Test the `ipalib.parameter.Param.validate` method. + """ + + # Test with required=True/False: + o = self.cls('my_param') + assert o.required is True + e = raises(errors2.RequirementError, o.validate, None) + assert e.name == 'my_param' + o = self.cls('my_param', required=False) + assert o.required is False + 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.parameter.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), + ] + class test_Bytes(ClassChecker): """ -- cgit From 11dce19225b2ebcf41adb9d06b402610226ab047 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 12 Jan 2009 22:48:04 -0700 Subject: New Param: added Param.get_default() method and detailed docstring; added corresponding unit tests --- tests/test_ipalib/test_parameter.py | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index b379379c..7f1b11ea 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -161,6 +161,7 @@ class test_Param(ClassChecker): 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.flags == frozenset() # Test that ValueError is raised when a kwarg from a subclass @@ -205,6 +206,26 @@ class test_Param(ClassChecker): 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.parameter.Param.__repr__` method. @@ -427,6 +448,64 @@ class test_Param(ClassChecker): (request.ugettext, False), ] + def test_get_default(self): + """ + Test the `ipalib.parameter.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_Bytes(ClassChecker): """ -- cgit From 33db9fee6017c0777f4fc5da8b020aefd714e387 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 13 Jan 2009 00:27:06 -0700 Subject: New Param: ported create_param() function and unit tests --- tests/test_ipalib/test_parameter.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 7f1b11ea..8abba496 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -748,3 +748,35 @@ class test_Str(ClassChecker): assert dummy.message == \ '%(name)s must be exactly %(length)d characters' dummy = dummy_ugettext(translation) + + +def test_create_param(): + """ + Test the `ipalib.parameter.create_param` function. + """ + f = parameter.create_param + + # Test that Param instances are returned unchanged: + params = ( + parameter.Param('one?'), + parameter.Int('two+'), + parameter.Str('three*'), + parameter.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) = parameter.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, parameter.Param, parameter.Str): + e = raises(TypeError, f, spec) + assert str(e) == \ + TYPE_ERROR % ('spec', (str, parameter.Param), spec, type(spec)) -- cgit From c2b0d03f82f16debcc55d34ac44197e0bc97e0e8 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 13 Jan 2009 01:07:33 -0700 Subject: New Param: updated Bytes and Str length rules to use new rule(_, value) calling signature; updated corresponding unit tests --- tests/test_ipalib/test_parameter.py | 142 ++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 70 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 8abba496..3a0bd0c1 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -569,78 +569,79 @@ class test_Bytes(ClassChecker): """ 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' + 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 m(dummy, name, value) is None - assert not hasattr(dummy, 'message') + assert rule(dummy, value) is None + assert dummy.called() is False - # 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' + # 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.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' + 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 m(dummy, name, value) is None - assert not hasattr(dummy, 'message') + assert rule(dummy, value) is None + assert dummy.called() is False - # 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' + # 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.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' + 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 m(dummy, name, value) is None - assert not hasattr(dummy, 'message') + assert rule(dummy, value) is None + assert dummy.called() is False # Test with failing values: - for value in ('ab', '123', '12345', 'abcdef'): + for value in ('ab', '123', '12345', 'sixsix'): assert_equal( - m(dummy, name, value), - translation % dict(name=name, length=4), + rule(dummy, value), + translation % dict(length=4), ) - assert dummy.message == \ - '%(name)s must be exactly %(length)d bytes' - dummy = dummy_ugettext(translation) + assert dummy.message == 'must be exactly %(length)d bytes' + assert dummy.called() is True + dummy.reset() class test_Str(ClassChecker): @@ -676,78 +677,79 @@ class test_Str(ClassChecker): """ 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' + 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 m(dummy, name, value) is None - assert not hasattr(dummy, 'message') + assert rule(dummy, value) is None + assert dummy.called() is False - # 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' + # 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.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' + 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 m(dummy, name, value) is None - assert not hasattr(dummy, 'message') + assert rule(dummy, value) is None + assert dummy.called() is False - # 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' + # 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.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' + 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 m(dummy, name, value) is None - assert not hasattr(dummy, 'message') + 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'abcdef'): + for value in (u'ab', u'123', u'12345', u'sixsix'): assert_equal( - m(dummy, name, value), - translation % dict(name=name, length=4), + rule(dummy, value), + translation % dict(length=4), ) - assert dummy.message == \ - '%(name)s must be exactly %(length)d characters' - dummy = dummy_ugettext(translation) + assert dummy.message == 'must be exactly %(length)d characters' + assert dummy.called() is True + dummy.reset() def test_create_param(): -- cgit From 10747103fa3748677e6e1948977de1313fe25bc9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 13 Jan 2009 02:17:16 -0700 Subject: New Param: implemented a base Param._convert_scalar() method; added Param.type_error attribute for ConversionError message --- tests/test_ipalib/test_parameter.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 3a0bd0c1..27d348b9 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -22,6 +22,7 @@ Test the `ipalib.parameter` 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 @@ -315,14 +316,14 @@ class test_Param(ClassChecker): """ Test the `ipalib.parameter.Param._convert_scalar` method. """ + dummy = dummy_ugettext() + + # Test with correct type: 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()' + 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): """ @@ -782,3 +783,17 @@ def test_create_param(): e = raises(TypeError, f, spec) assert str(e) == \ TYPE_ERROR % ('spec', (str, parameter.Param), spec, type(spec)) + + +def test_messages(): + """ + Test module level message in `ipalib.parameter`. + """ + for name in dir(parameter): + if name.startswith('_'): + continue + attr = getattr(parameter, name) + if not (isclass(attr) and issubclass(attr, parameter.Param)): + continue + assert type(attr.type_error) is str + assert attr.type_error in parameter.__messages -- cgit From a0fb215a2c5f2dfaf26b06f93c3a651f2420083d Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 13 Jan 2009 18:29:45 -0700 Subject: New Param: updated Str._convert_scalar() so it raises a ConversionError --- tests/test_ipalib/test_parameter.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 27d348b9..47cea89d 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -667,12 +667,18 @@ class test_Str(ClassChecker): 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 + 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): """ -- cgit From 659bb4c142ee9a987babd38fad93b539e51309f3 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 13 Jan 2009 19:49:23 -0700 Subject: New Param: added Param.clone() method and corresponding unit test --- tests/test_ipalib/test_parameter.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 47cea89d..8c4a93ab 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -239,6 +239,41 @@ class test_Param(ClassChecker): o = self.cls('name', multivalue=True) assert repr(o) == "Param('name', multivalue=True)" + def test_clone(self): + """ + Test the `ipalib.parameter.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.parameter.get_label` method. -- cgit From 8cc38e681f9caca838540511664337f964302f56 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 13 Jan 2009 20:27:19 -0700 Subject: New Param: added new Flag param class and its unit test --- tests/test_ipalib/test_parameter.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 8c4a93ab..4a6fee55 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -163,6 +163,7 @@ class test_Param(ClassChecker): 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.flags == frozenset() # Test that ValueError is raised when a kwarg from a subclass @@ -543,6 +544,33 @@ class test_Param(ClassChecker): assert o.normalizer.value is default +class test_Flag(ClassChecker): + """ + Test the `ipalib.parameter.Flag` class. + """ + _cls = parameter.Flag + + def test_init(self): + """ + Test the `ipalib.parameter.Flag.__init__` method. + """ + o = self.cls('my_flag') + assert o.type is bool + assert isinstance(o, parameter.Bool) + assert o.autofill is True + + # Test with autofill=False + o = self.cls('my_flag', autofill=False) + assert o.autofill 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 is not orig + assert type(clone) is self.cls + + class test_Bytes(ClassChecker): """ Test the `ipalib.parameter.Bytes` class. -- cgit From 05514292dcf2448f0340e09cd0da88f815c43c5b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 09:56:10 -0700 Subject: New Param: Flag now fill-in default=False and also forces default to be a bool --- tests/test_ipalib/test_parameter.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py index 4a6fee55..d98888ab 100644 --- a/tests/test_ipalib/test_parameter.py +++ b/tests/test_ipalib/test_parameter.py @@ -554,22 +554,38 @@ class test_Flag(ClassChecker): """ Test the `ipalib.parameter.Flag.__init__` method. """ + # Test with no kwargs: o = self.cls('my_flag') assert o.type is bool assert isinstance(o, parameter.Bool) assert o.autofill is True + assert o.default is False - # Test with autofill=False - o = self.cls('my_flag', autofill=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_Bytes(ClassChecker): """ -- cgit From 5d1e5a0aa9f79e179a5538dcf1bcec5426369951 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 10:25:33 -0700 Subject: New Param: renamed parameter.py to parameters.py --- tests/test_ipalib/test_parameter.py | 884 ----------------------------------- tests/test_ipalib/test_parameters.py | 884 +++++++++++++++++++++++++++++++++++ 2 files changed, 884 insertions(+), 884 deletions(-) delete mode 100644 tests/test_ipalib/test_parameter.py create mode 100644 tests/test_ipalib/test_parameters.py (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameter.py b/tests/test_ipalib/test_parameter.py deleted file mode 100644 index d98888ab..00000000 --- a/tests/test_ipalib/test_parameter.py +++ /dev/null @@ -1,884 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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 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 parameter, request, errors2 -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 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.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.create_default is None - assert o._get_default is None - assert o.autofill 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.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_clone(self): - """ - Test the `ipalib.parameter.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.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. - """ - 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.parameter.Param.validate` method. - """ - - # Test with required=True/False: - o = self.cls('my_param') - assert o.required is True - e = raises(errors2.RequirementError, o.validate, None) - assert e.name == 'my_param' - o = self.cls('my_param', required=False) - assert o.required is False - 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.parameter.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.parameter.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.parameter.Flag` class. - """ - _cls = parameter.Flag - - def test_init(self): - """ - Test the `ipalib.parameter.Flag.__init__` method. - """ - # Test with no kwargs: - o = self.cls('my_flag') - assert o.type is bool - assert isinstance(o, parameter.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_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. - """ - 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.parameter.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.parameter.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.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') - 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.parameter.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.parameter.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.parameter.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.parameter.create_param` function. - """ - f = parameter.create_param - - # Test that Param instances are returned unchanged: - params = ( - parameter.Param('one?'), - parameter.Int('two+'), - parameter.Str('three*'), - parameter.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) = parameter.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, parameter.Param, parameter.Str): - e = raises(TypeError, f, spec) - assert str(e) == \ - TYPE_ERROR % ('spec', (str, parameter.Param), spec, type(spec)) - - -def test_messages(): - """ - Test module level message in `ipalib.parameter`. - """ - for name in dir(parameter): - if name.startswith('_'): - continue - attr = getattr(parameter, name) - if not (isclass(attr) and issubclass(attr, parameter.Param)): - continue - assert type(attr.type_error) is str - assert attr.type_error in parameter.__messages diff --git a/tests/test_ipalib/test_parameters.py b/tests/test_ipalib/test_parameters.py new file mode 100644 index 00000000..d98888ab --- /dev/null +++ b/tests/test_ipalib/test_parameters.py @@ -0,0 +1,884 @@ +# Authors: +# Jason Gerard DeRose +# +# 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 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 parameter, request, errors2 +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 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.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.create_default is None + assert o._get_default is None + assert o.autofill 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.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_clone(self): + """ + Test the `ipalib.parameter.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.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. + """ + 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.parameter.Param.validate` method. + """ + + # Test with required=True/False: + o = self.cls('my_param') + assert o.required is True + e = raises(errors2.RequirementError, o.validate, None) + assert e.name == 'my_param' + o = self.cls('my_param', required=False) + assert o.required is False + 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.parameter.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.parameter.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.parameter.Flag` class. + """ + _cls = parameter.Flag + + def test_init(self): + """ + Test the `ipalib.parameter.Flag.__init__` method. + """ + # Test with no kwargs: + o = self.cls('my_flag') + assert o.type is bool + assert isinstance(o, parameter.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_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. + """ + 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.parameter.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.parameter.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.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') + 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.parameter.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.parameter.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.parameter.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.parameter.create_param` function. + """ + f = parameter.create_param + + # Test that Param instances are returned unchanged: + params = ( + parameter.Param('one?'), + parameter.Int('two+'), + parameter.Str('three*'), + parameter.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) = parameter.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, parameter.Param, parameter.Str): + e = raises(TypeError, f, spec) + assert str(e) == \ + TYPE_ERROR % ('spec', (str, parameter.Param), spec, type(spec)) + + +def test_messages(): + """ + Test module level message in `ipalib.parameter`. + """ + for name in dir(parameter): + if name.startswith('_'): + continue + attr = getattr(parameter, name) + if not (isclass(attr) and issubclass(attr, parameter.Param)): + continue + assert type(attr.type_error) is str + assert attr.type_error in parameter.__messages -- cgit From 3a6f716aac6c2750f42a04eba18f1023b866b790 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 10:29:18 -0700 Subject: Updated all references to 'parameter' module to 'parameters' --- tests/test_ipalib/test_parameters.py | 100 +++++++++++++++++------------------ 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameters.py b/tests/test_ipalib/test_parameters.py index d98888ab..f7ee2cac 100644 --- a/tests/test_ipalib/test_parameters.py +++ b/tests/test_ipalib/test_parameters.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Test the `ipalib.parameter` module. +Test the `ipalib.parameters` module. """ from types import NoneType @@ -26,19 +26,19 @@ 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 parameter, request, errors2 +from ipalib import parameters, request, errors2 from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR, NULLS class test_DefaultFrom(ClassChecker): """ - Test the `ipalib.parameter.DefaultFrom` class. + Test the `ipalib.parameters.DefaultFrom` class. """ - _cls = parameter.DefaultFrom + _cls = parameters.DefaultFrom def test_init(self): """ - Test the `ipalib.parameter.DefaultFrom.__init__` method. + Test the `ipalib.parameters.DefaultFrom.__init__` method. """ def callback(*args): return args @@ -60,7 +60,7 @@ class test_DefaultFrom(ClassChecker): def test_call(self): """ - Test the `ipalib.parameter.DefaultFrom.__call__` method. + Test the `ipalib.parameters.DefaultFrom.__call__` method. """ def callback(givenname, sn): return givenname[0] + sn[0] @@ -95,9 +95,9 @@ class test_DefaultFrom(ClassChecker): def test_parse_param_spec(): """ - Test the `ipalib.parameter.parse_param_spec` function. + Test the `ipalib.parameters.parse_param_spec` function. """ - f = parameter.parse_param_spec + 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)) @@ -131,13 +131,13 @@ class DummyRule(object): class test_Param(ClassChecker): """ - Test the `ipalib.parameter.Param` class. + Test the `ipalib.parameters.Param` class. """ - _cls = parameter.Param + _cls = parameters.Param def test_init(self): """ - Test the `ipalib.parameter.Param.__init__` method. + Test the `ipalib.parameters.Param.__init__` method. """ name = 'my_param' o = self.cls(name) @@ -230,7 +230,7 @@ class test_Param(ClassChecker): def test_repr(self): """ - Test the `ipalib.parameter.Param.__repr__` method. + Test the `ipalib.parameters.Param.__repr__` method. """ for name in ['name', 'name?', 'name*', 'name+']: o = self.cls(name) @@ -242,7 +242,7 @@ class test_Param(ClassChecker): def test_clone(self): """ - Test the `ipalib.parameter.Param.clone` method. + Test the `ipalib.parameters.Param.clone` method. """ # Test with the defaults orig = self.cls('my_param') @@ -277,7 +277,7 @@ class test_Param(ClassChecker): def test_get_label(self): """ - Test the `ipalib.parameter.get_label` method. + Test the `ipalib.parameters.get_label` method. """ context = request.context cli_name = 'the_cli_name' @@ -321,7 +321,7 @@ class test_Param(ClassChecker): def test_convert(self): """ - Test the `ipalib.parameter.Param.convert` method. + Test the `ipalib.parameters.Param.convert` method. """ okay = ('Hello', u'Hello', 0, 4.2, True, False) class Subclass(self.cls): @@ -350,7 +350,7 @@ class test_Param(ClassChecker): def test_convert_scalar(self): """ - Test the `ipalib.parameter.Param._convert_scalar` method. + Test the `ipalib.parameters.Param._convert_scalar` method. """ dummy = dummy_ugettext() @@ -363,7 +363,7 @@ class test_Param(ClassChecker): def test_validate(self): """ - Test the `ipalib.parameter.Param.validate` method. + Test the `ipalib.parameters.Param.validate` method. """ # Test with required=True/False: @@ -441,7 +441,7 @@ class test_Param(ClassChecker): def test_validate_scalar(self): """ - Test the `ipalib.parameter.Param._validate_scalar` method. + Test the `ipalib.parameters.Param._validate_scalar` method. """ class MyParam(self.cls): type = bool @@ -487,7 +487,7 @@ class test_Param(ClassChecker): def test_get_default(self): """ - Test the `ipalib.parameter.Param._get_default` method. + Test the `ipalib.parameters.Param._get_default` method. """ class PassThrough(object): value = None @@ -546,18 +546,18 @@ class test_Param(ClassChecker): class test_Flag(ClassChecker): """ - Test the `ipalib.parameter.Flag` class. + Test the `ipalib.parameters.Flag` class. """ - _cls = parameter.Flag + _cls = parameters.Flag def test_init(self): """ - Test the `ipalib.parameter.Flag.__init__` method. + Test the `ipalib.parameters.Flag.__init__` method. """ # Test with no kwargs: o = self.cls('my_flag') assert o.type is bool - assert isinstance(o, parameter.Bool) + assert isinstance(o, parameters.Bool) assert o.autofill is True assert o.default is False @@ -589,13 +589,13 @@ class test_Flag(ClassChecker): class test_Bytes(ClassChecker): """ - Test the `ipalib.parameter.Bytes` class. + Test the `ipalib.parameters.Bytes` class. """ - _cls = parameter.Bytes + _cls = parameters.Bytes def test_init(self): """ - Test the `ipalib.parameter.Bytes.__init__` method. + Test the `ipalib.parameters.Bytes.__init__` method. """ o = self.cls('my_bytes') assert o.type is str @@ -647,7 +647,7 @@ class test_Bytes(ClassChecker): def test_rule_minlength(self): """ - Test the `ipalib.parameter.Bytes._rule_minlength` method. + Test the `ipalib.parameters.Bytes._rule_minlength` method. """ o = self.cls('my_bytes', minlength=3) assert o.minlength == 3 @@ -673,7 +673,7 @@ class test_Bytes(ClassChecker): def test_rule_maxlength(self): """ - Test the `ipalib.parameter.Bytes._rule_maxlength` method. + Test the `ipalib.parameters.Bytes._rule_maxlength` method. """ o = self.cls('my_bytes', maxlength=4) assert o.maxlength == 4 @@ -699,7 +699,7 @@ class test_Bytes(ClassChecker): def test_rule_length(self): """ - Test the `ipalib.parameter.Bytes._rule_length` method. + Test the `ipalib.parameters.Bytes._rule_length` method. """ o = self.cls('my_bytes', length=4) assert o.length == 4 @@ -726,13 +726,13 @@ class test_Bytes(ClassChecker): class test_Str(ClassChecker): """ - Test the `ipalib.parameter.Str` class. + Test the `ipalib.parameters.Str` class. """ - _cls = parameter.Str + _cls = parameters.Str def test_init(self): """ - Test the `ipalib.parameter.Str.__init__` method. + Test the `ipalib.parameters.Str.__init__` method. """ o = self.cls('my_str') assert o.type is unicode @@ -743,7 +743,7 @@ class test_Str(ClassChecker): def test_convert_scalar(self): """ - Test the `ipalib.parameter.Str._convert_scalar` method. + Test the `ipalib.parameters.Str._convert_scalar` method. """ o = self.cls('my_str') mthd = o._convert_scalar @@ -761,7 +761,7 @@ class test_Str(ClassChecker): def test_rule_minlength(self): """ - Test the `ipalib.parameter.Str._rule_minlength` method. + Test the `ipalib.parameters.Str._rule_minlength` method. """ o = self.cls('my_str', minlength=3) assert o.minlength == 3 @@ -787,7 +787,7 @@ class test_Str(ClassChecker): def test_rule_maxlength(self): """ - Test the `ipalib.parameter.Str._rule_maxlength` method. + Test the `ipalib.parameters.Str._rule_maxlength` method. """ o = self.cls('my_str', maxlength=4) assert o.maxlength == 4 @@ -813,7 +813,7 @@ class test_Str(ClassChecker): def test_rule_length(self): """ - Test the `ipalib.parameter.Str._rule_length` method. + Test the `ipalib.parameters.Str._rule_length` method. """ o = self.cls('my_str', length=4) assert o.length == 4 @@ -840,23 +840,23 @@ class test_Str(ClassChecker): def test_create_param(): """ - Test the `ipalib.parameter.create_param` function. + Test the `ipalib.parameters.create_param` function. """ - f = parameter.create_param + f = parameters.create_param # Test that Param instances are returned unchanged: params = ( - parameter.Param('one?'), - parameter.Int('two+'), - parameter.Str('three*'), - parameter.Bytes('four'), + 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) = parameter.parse_param_spec(spec) + (name, kw) = parameters.parse_param_spec(spec) p = f(spec) assert p.param_spec is spec assert p.name == name @@ -864,21 +864,21 @@ def test_create_param(): 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, parameter.Param, parameter.Str): + for spec in (u'one', 42, parameters.Param, parameters.Str): e = raises(TypeError, f, spec) assert str(e) == \ - TYPE_ERROR % ('spec', (str, parameter.Param), spec, type(spec)) + TYPE_ERROR % ('spec', (str, parameters.Param), spec, type(spec)) def test_messages(): """ - Test module level message in `ipalib.parameter`. + Test module level message in `ipalib.parameters`. """ - for name in dir(parameter): + for name in dir(parameters): if name.startswith('_'): continue - attr = getattr(parameter, name) - if not (isclass(attr) and issubclass(attr, parameter.Param)): + 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 parameter.__messages + assert attr.type_error in parameters.__messages -- cgit From 3e201dfff6d96f415a7f7d7f6010e97877b5a5c0 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 10:58:05 -0700 Subject: New Param: split common Bytes/Str functionality into new Data base class; Str no longer subclasses from Bytes --- tests/test_ipalib/test_parameters.py | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameters.py b/tests/test_ipalib/test_parameters.py index f7ee2cac..aeaed2a4 100644 --- a/tests/test_ipalib/test_parameters.py +++ b/tests/test_ipalib/test_parameters.py @@ -587,6 +587,59 @@ class test_Flag(ClassChecker): 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. -- cgit From 47e8b1c0b75b19765d8682e52dcdcfcd66b7760b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 11:25:26 -0700 Subject: Removed deprecited ipa_types.py and test_ipa_types.py --- tests/test_ipalib/test_ipa_types.py | 430 ------------------------------------ 1 file changed, 430 deletions(-) delete mode 100644 tests/test_ipalib/test_ipa_types.py (limited to 'tests/test_ipalib') 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 -# -# 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' -- cgit From 2b2e73e7df90d38175e035d6ada4d752120dc0ec Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 11:39:29 -0700 Subject: Removed depreciated code from frontend.py; frontend.py no longer imports ipa_types --- tests/test_ipalib/test_frontend.py | 414 ------------------------------------- 1 file changed, 414 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 94e586fe..c4093317 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -70,420 +70,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. -- cgit From 69acff450c043bdd7d70da473c3adafdd9d3fe03 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 12:00:47 -0700 Subject: New Param: removed more depreciated 'import ipa_types' --- tests/test_ipalib/test_frontend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index c4093317..4a0e48d0 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -23,7 +23,7 @@ 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 ipalib import frontend, backend, plugable, errors, parameters, config def test_RULE_FLAG(): -- cgit From 09e2f5d615a17943ba572fd02a2e0d9b15ca1076 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 13:17:30 -0700 Subject: New Param: got most of unit tests ported (still have 6 errors); haven't ported doctests yet --- tests/test_ipalib/test_frontend.py | 76 +++++++++++++------------------------- 1 file changed, 26 insertions(+), 50 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 4a0e48d0..6b3e0f71 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -23,6 +23,7 @@ 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.constants import TYPE_ERROR from ipalib import frontend, backend, plugable, errors, parameters, config @@ -89,24 +90,21 @@ class test_Command(ClassChecker): if value != self.name: return 'must equal %s' % 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, + frontend.Param('option0', Rule('option0'), + normalizer=normalizer, default_from=default_from, - rules=(Rule('option0'),) ), - frontend.Param('option1', - normalize=normalize, + frontend.Param('option1', Rule('option1'), + normalizer=normalizer, default_from=default_from, - rules=(Rule('option1'),), - required=True, ), ) return example @@ -163,8 +161,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 @@ -172,8 +170,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')) @@ -213,8 +211,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 @@ -257,22 +255,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): """ @@ -431,9 +414,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): @@ -442,9 +425,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)) @@ -560,7 +543,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 @@ -587,15 +570,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 @@ -605,10 +586,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) @@ -741,12 +722,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): """ @@ -756,7 +732,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' -- cgit From 79422d048959a7f6a5fff981caf91de924788e85 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 13:51:37 -0700 Subject: All unit tests now working (except for doctests and Rob's xmlrpc tests) --- tests/test_ipalib/test_frontend.py | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 6b3e0f71..071a70fd 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -23,8 +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 tests.util import assert_equal from ipalib.constants import TYPE_ERROR -from ipalib import frontend, backend, plugable, errors, parameters, config +from ipalib import frontend, backend, plugable, errors2, errors, parameters, config def test_RULE_FLAG(): @@ -86,9 +87,9 @@ 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 = parameters.DefaultFrom( lambda arg: arg, @@ -98,11 +99,11 @@ class test_Command(ClassChecker): class example(self.cls): takes_options = ( - frontend.Param('option0', Rule('option0'), + parameters.Str('option0', Rule('option0'), normalizer=normalizer, default_from=default_from, ), - frontend.Param('option1', Rule('option1'), + parameters.Str('option1', Rule('option1'), normalizer=normalizer, default_from=default_from, ), @@ -224,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): """ @@ -266,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', @@ -274,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 -- cgit From cd3508bacee20c01640964470b0c623691b3c216 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 14:04:05 -0700 Subject: New Param: added Param.query kwarg for crud operations like Retrieve and Search where criteria should not be validated --- tests/test_ipalib/test_parameters.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameters.py b/tests/test_ipalib/test_parameters.py index aeaed2a4..f9e370fe 100644 --- a/tests/test_ipalib/test_parameters.py +++ b/tests/test_ipalib/test_parameters.py @@ -164,6 +164,7 @@ class test_Param(ClassChecker): 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 @@ -366,15 +367,21 @@ class test_Param(ClassChecker): Test the `ipalib.parameters.Param.validate` method. """ - # Test with required=True/False: + # Test in default state (with no rules, no kwarg): o = self.cls('my_param') - assert o.required is True 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, []) -- cgit From 6be5e4a0a55c1ba048444430afc0e01b3048d8b9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 15 Jan 2009 23:52:50 -0700 Subject: ipalib.rpc: now using allow_none=True after conversation with Rob; added xml_dumps() and xml_loads() functions; some name cleanup --- tests/test_ipalib/test_rpc.py | 108 +++++++++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 22 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_rpc.py b/tests/test_ipalib/test_rpc.py index 614db607..eba35261 100644 --- a/tests/test_ipalib/test_rpc.py +++ b/tests/test_ipalib/test_rpc.py @@ -21,64 +21,68 @@ Test the `ipalib.rpc` module. """ -from xmlrpclib import Binary, dumps, loads -from tests.util import raises +from xmlrpclib import Binary, Fault, dumps, loads +from tests.util import raises, assert_equal from tests.data import binary_bytes, utf8_bytes, unicode_str from ipalib import rpc def dump_n_load(value): (param, method) = loads( - dumps((value,)) + dumps((value,), allow_none=True) ) return param[0] def round_trip(value): - return rpc.xmlrpc_unwrap( - dump_n_load(rpc.xmlrpc_wrap(value)) + return rpc.xml_unwrap( + dump_n_load(rpc.xml_wrap(value)) ) def test_round_trip(): """ - Test `ipalib.rpc.xmlrpc_wrap` and `ipalib.rpc.xmlrpc_unwrap`. + Test `ipalib.rpc.xml_wrap` and `ipalib.rpc.xml_unwrap`. This tests the two functions together with ``xmlrpclib.dumps()`` and ``xmlrpclib.loads()`` in a full wrap/dumps/loads/unwrap round trip. """ # We first test that our assumptions about xmlrpclib module in the Python # standard library are correct: - assert dump_n_load(utf8_bytes) == unicode_str - assert dump_n_load(unicode_str) == unicode_str - assert dump_n_load(Binary(binary_bytes)).data == binary_bytes + assert_equal(dump_n_load(utf8_bytes), unicode_str) + assert_equal(dump_n_load(unicode_str), unicode_str) + assert_equal(dump_n_load(Binary(binary_bytes)).data, binary_bytes) assert isinstance(dump_n_load(Binary(binary_bytes)), Binary) assert type(dump_n_load('hello')) is str assert type(dump_n_load(u'hello')) is str + assert_equal(dump_n_load(''), '') + assert_equal(dump_n_load(u''), '') + assert dump_n_load(None) is None # Now we test our wrap and unwrap methods in combination with dumps, loads: # All str should come back str (because they get wrapped in # xmlrpclib.Binary(). All unicode should come back unicode because str - # explicity get decoded by rpc.xmlrpc_unwrap() if they weren't already + # explicity get decoded by rpc.xml_unwrap() if they weren't already # decoded by xmlrpclib.loads(). - assert round_trip(utf8_bytes) == utf8_bytes - assert round_trip(unicode_str) == unicode_str - assert round_trip(binary_bytes) == binary_bytes + assert_equal(round_trip(utf8_bytes), utf8_bytes) + assert_equal(round_trip(unicode_str), unicode_str) + assert_equal(round_trip(binary_bytes), binary_bytes) assert type(round_trip('hello')) is str assert type(round_trip(u'hello')) is unicode - assert round_trip('') == '' - assert round_trip(u'') == u'' - compound = [utf8_bytes, unicode_str, binary_bytes, + assert_equal(round_trip(''), '') + assert_equal(round_trip(u''), u'') + assert round_trip(None) is None + compound = [utf8_bytes, None, binary_bytes, (None, unicode_str), dict(utf8=utf8_bytes, chars=unicode_str, data=binary_bytes) ] assert round_trip(compound) == tuple(compound) -def test_xmlrpc_wrap(): +def test_xml_wrap(): """ - Test the `ipalib.rpc.xmlrpc_wrap` function. + Test the `ipalib.rpc.xml_wrap` function. """ - f = rpc.xmlrpc_wrap + f = rpc.xml_wrap assert f([]) == tuple() assert f({}) == dict() b = f('hello') @@ -90,11 +94,11 @@ def test_xmlrpc_wrap(): value = f([dict(one=False, two=u'hello'), None, 'hello']) -def test_xmlrpc_unwrap(): +def test_xml_unwrap(): """ - Test the `ipalib.rpc.xmlrpc_unwrap` function. + Test the `ipalib.rpc.xml_unwrap` function. """ - f = rpc.xmlrpc_unwrap + f = rpc.xml_unwrap assert f([]) == tuple() assert f({}) == dict() value = f(Binary(utf8_bytes)) @@ -106,3 +110,63 @@ def test_xmlrpc_unwrap(): assert value == (True, 'hello', dict(one=1, two=unicode_str, three=None)) assert type(value[1]) is str assert type(value[2]['two']) is unicode + + +def test_xml_dumps(): + """ + Test the `ipalib.rpc.xml_dumps` function. + """ + f = rpc.xml_dumps + params = (binary_bytes, utf8_bytes, unicode_str, None) + + # Test serializing an RPC request: + data = f(params, 'the_method') + (p, m) = loads(data) + assert_equal(m, u'the_method') + assert type(p) is tuple + assert rpc.xml_unwrap(p) == params + + # Test serializing an RPC response: + data = f((params,), methodresponse=True) + (tup, m) = loads(data) + assert m is None + assert len(tup) == 1 + assert type(tup) is tuple + assert rpc.xml_unwrap(tup[0]) == params + + # Test serializing an RPC response containing a Fault: + fault = Fault(69, unicode_str) + data = f(fault, methodresponse=True) + e = raises(Fault, loads, data) + assert e.faultCode == 69 + assert_equal(e.faultString, unicode_str) + + +def test_xml_loads(): + """ + Test the `ipalib.rpc.xml_loads` function. + """ + f = rpc.xml_loads + params = (binary_bytes, utf8_bytes, unicode_str, None) + wrapped = rpc.xml_wrap(params) + + # Test un-serializing an RPC request: + data = dumps(wrapped, 'the_method', allow_none=True) + (p, m) = f(data) + assert_equal(m, u'the_method') + assert_equal(p, params) + + # Test un-serializing an RPC response: + data = dumps((wrapped,), methodresponse=True, allow_none=True) + (tup, m) = f(data) + assert m is None + assert len(tup) == 1 + assert type(tup) is tuple + assert_equal(tup[0], params) + + # Test un-serializing an RPC response containing a Fault: + fault = Fault(69, unicode_str) + data = dumps(fault, methodresponse=True, allow_none=True) + e = raises(Fault, f, data) + assert e.faultCode == 69 + assert_equal(e.faultString, unicode_str) -- cgit From 364e05def194b80714a5ea2a3e89598db9fb4892 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 18 Jan 2009 15:55:56 -0700 Subject: Added missing enumerable parameters --- tests/test_ipalib/test_parameters.py | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameters.py b/tests/test_ipalib/test_parameters.py index f9e370fe..e6868d0d 100644 --- a/tests/test_ipalib/test_parameters.py +++ b/tests/test_ipalib/test_parameters.py @@ -898,6 +898,55 @@ class test_Str(ClassChecker): dummy.reset() +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 + ) + + 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=%(values)s' + 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)r') + dummy.reset() + + def test_create_param(): """ Test the `ipalib.parameters.create_param` function. -- cgit From 55fba5420d8ea57931937728102094492ca73d86 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 19 Jan 2009 21:10:42 -0700 Subject: Added rpc.xmlclient backend plugin for forwarding; added corresponding unit tests --- tests/test_ipalib/test_rpc.py | 81 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_rpc.py b/tests/test_ipalib/test_rpc.py index eba35261..296e9bc1 100644 --- a/tests/test_ipalib/test_rpc.py +++ b/tests/test_ipalib/test_rpc.py @@ -21,10 +21,16 @@ Test the `ipalib.rpc` module. """ +import threading from xmlrpclib import Binary, Fault, dumps, loads -from tests.util import raises, assert_equal +from tests.util import raises, assert_equal, PluginTester, DummyClass from tests.data import binary_bytes, utf8_bytes, unicode_str -from ipalib import rpc +from ipalib.frontend import Command +from ipalib.request import context +from ipalib import rpc, errors2 + + +std_compound = (binary_bytes, utf8_bytes, unicode_str) def dump_n_load(value): @@ -170,3 +176,74 @@ def test_xml_loads(): e = raises(Fault, f, data) assert e.faultCode == 69 assert_equal(e.faultString, unicode_str) + + +class test_xmlclient(PluginTester): + """ + Test the `ipalib.rpc.xmlclient` plugin. + """ + _plugin = rpc.xmlclient + + def test_forward(self): + """ + Test the `ipalib.rpc.xmlclient.forward` method. + """ + class user_add(Command): + pass + + # Test that ValueError is raised when forwarding a command that is not + # in api.Command: + (o, api, home) = self.instance('Backend', in_server=False) + e = raises(ValueError, o.forward, 'user_add') + assert str(e) == '%s.forward(): %r not in api.Command' % ( + 'xmlclient', 'user_add' + ) + + # Test that StandardError is raised when context.xmlconn does not exist: + (o, api, home) = self.instance('Backend', user_add, in_server=False) + e = raises(StandardError, o.forward, 'user_add') + assert str(e) == '%s.forward(%r): need context.xmlconn in thread %r' % ( + 'xmlclient', 'user_add', threading.currentThread().getName() + ) + + args = (binary_bytes, utf8_bytes, unicode_str) + kw = dict(one=binary_bytes, two=utf8_bytes, three=unicode_str) + params = args + (kw,) + result = (unicode_str, binary_bytes, utf8_bytes) + context.xmlconn = DummyClass( + ( + 'user_add', + (rpc.xml_wrap(params),), + {}, + rpc.xml_wrap(result), + ), + ( + 'user_add', + (rpc.xml_wrap(params),), + {}, + Fault(3005, u"'four' is required"), # RequirementError + ), + ( + 'user_add', + (rpc.xml_wrap(params),), + {}, + Fault(700, u'no such error'), # There is no error 700 + ), + + ) + + # Test with a successful return value: + assert o.forward('user_add', *args, **kw) == result + + # Test with an errno the client knows: + e = raises(errors2.RequirementError, o.forward, 'user_add', *args, **kw) + assert_equal(e.message, u"'four' is required") + + # Test with an errno the client doesn't know + e = raises(errors2.UnknownError, o.forward, 'user_add', *args, **kw) + assert_equal(e.code, 700) + assert_equal(e.error, u'no such error') + + assert context.xmlconn._calledall() is True + + del context.xmlconn -- cgit From f22f3eabb20e6c46f78ba5c40d75bb52b7872060 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 20 Jan 2009 09:38:39 -0700 Subject: Fixed Param.validate() so that self.query is checked after self.required --- tests/test_ipalib/test_parameters.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tests/test_ipalib') diff --git a/tests/test_ipalib/test_parameters.py b/tests/test_ipalib/test_parameters.py index e6868d0d..261e1481 100644 --- a/tests/test_ipalib/test_parameters.py +++ b/tests/test_ipalib/test_parameters.py @@ -380,7 +380,8 @@ class test_Param(ClassChecker): # Test with query=True: o = self.cls('my_param', query=True) assert o.query is True - assert o.validate(None) is None + e = raises(errors2.RequirementError, o.validate, None) + assert_equal(e.name, 'my_param') # Test with multivalue=True: o = self.cls('my_param', multivalue=True) -- cgit