summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
authorJason Gerard DeRose <jderose@redhat.com>2008-08-08 19:53:45 +0000
committerJason Gerard DeRose <jderose@redhat.com>2008-08-08 19:53:45 +0000
commitd171dc90111cad91884c3a1b3afdb8b16b7c289e (patch)
treed23cd4b163c99ec1cfa57934f6426632c3d9c8ec /ipalib
parent8e468248155947075689e6d01c3ab90fbd9f1643 (diff)
downloadfreeipa.git-d171dc90111cad91884c3a1b3afdb8b16b7c289e.tar.gz
freeipa.git-d171dc90111cad91884c3a1b3afdb8b16b7c289e.tar.xz
freeipa.git-d171dc90111cad91884c3a1b3afdb8b16b7c289e.zip
82: Cleaned up unit tests for public.option; added some doodles in plugable.Base
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/plugable.py17
-rw-r--r--ipalib/public.py12
-rw-r--r--ipalib/tests/test_public.py72
3 files changed, 77 insertions, 24 deletions
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
index c3eb409b..4032b574 100644
--- a/ipalib/plugable.py
+++ b/ipalib/plugable.py
@@ -54,6 +54,23 @@ def check_identifier(name):
raise errors.NameSpaceError(name, regex)
+class Abstract(object):
+ __public__ = frozenset()
+
+ @classmethod
+ def implements(cls, arg):
+ assert type(cls.__public__) is frozenset
+ if isinstance(arg, str):
+ return arg in cls.__public__
+ if type(getattr(arg, '__public__', None)) is frozenset:
+ return cls.__public__.issuperset(arg.__public__)
+ if type(arg) is frozenset:
+ return cls.__public__.issuperset(arg)
+ raise TypeError(
+ "must be str, frozenset, or have frozenset '__public__' attribute"
+ )
+
+
class Plugin(object):
"""
Base class for all plugins.
diff --git a/ipalib/public.py b/ipalib/public.py
index 6f7f2154..1c6f9e7f 100644
--- a/ipalib/public.py
+++ b/ipalib/public.py
@@ -102,7 +102,7 @@ class option(object):
def __rules_iter(self):
"""
Iterates through the attributes in this instance to retrieve the
- methods implemented validation rules.
+ methods implementing validation rules.
"""
for name in dir(self.__class__):
if name.startswith('_'):
@@ -117,6 +117,10 @@ class option(object):
"""
Returns a default or auto-completed value for this option. If no
default is available, this method should return None.
+
+ All the keywords are passed so it's possible to build an
+ auto-completed value from other options values, e.g., build 'initials'
+ from 'givenname' + 'sn'.
"""
return None
@@ -177,11 +181,15 @@ class cmd(plugable.Plugin):
self.options.validate(value)
def default(self, **kw):
+ d = {}
for opt in self.options:
if opt.name not in kw:
value = opt.default(**kw)
if value is not None:
- kw[opt.name] = value
+ d[opt.name] = value
+ assert not set(kw).intersection(d)
+ kw.update(d)
+ return kw
def __call__(self, **kw):
(args, kw) = self.normalize(*args, **kw)
diff --git a/ipalib/tests/test_public.py b/ipalib/tests/test_public.py
index f396eed2..49fbb17f 100644
--- a/ipalib/tests/test_public.py
+++ b/ipalib/tests/test_public.py
@@ -63,13 +63,35 @@ def test_is_rule():
assert not is_rule(call(None))
-class test_option():
- def cls(self):
- return public.option
+class ClassChecker(object):
+ __cls = None
+ __subcls = None
- def sub(self):
+ def __get_cls(self):
+ if self.__cls is None:
+ self.__cls = self._cls
+ return self.__cls
+ cls = property(__get_cls)
+
+ def __get_subcls(self):
+ if self.__subcls is None:
+ self.__subcls = self.get_subcls()
+ return self.__subcls
+ subcls = property(__get_subcls)
+
+ def get_subcls(self):
+ raise NotImplementedError(
+ self.__class__.__name__,
+ 'get_subcls()'
+ )
+
+
+class test_option(ClassChecker):
+ _cls = public.option
+
+ def get_subcls(self):
rule = public.rule
- class int_opt(self.cls()):
+ class int_opt(self.cls):
type = int
@rule
def rule_0(self, value):
@@ -89,13 +111,12 @@ class test_option():
"""
Perform some tests on the class (not an instance).
"""
- cls = self.cls()
#assert issubclass(cls, plugable.ReadOnly)
- assert type(cls.rules) is property
+ assert type(self.cls.rules) is property
def test_normalize(self):
- sub = self.sub()
- i = sub()
+ assert 'normalize' in self.cls.__public__
+ o = self.subcls()
# Test with values that can't be converted:
nope = (
'7.0'
@@ -104,7 +125,7 @@ class test_option():
None,
)
for val in nope:
- e = raises(errors.NormalizationError, i.normalize, val)
+ e = raises(errors.NormalizationError, o.normalize, val)
assert isinstance(e, errors.ValidationError)
assert e.name == 'int_opt'
assert e.value == val
@@ -120,29 +141,36 @@ class test_option():
' 7 ',
)
for val in okay:
- assert i.normalize(val) == 7
+ assert o.normalize(val) == 7
+
+ def test_validate(self):
+ """
+ Test the validate method.
+ """
+ assert 'validate' in self.cls.__public__
+ o = self.subcls()
+ o.validate(9)
+ for i in xrange(3):
+ e = raises(errors.RuleError, o.validate, i)
+ assert e.error == 'cannot be %d' % i
+ assert e.value == i
def test_rules(self):
"""
Test the rules property.
"""
- o = self.sub()()
+ o = self.subcls()
assert len(o.rules) == 3
def get_rule(i):
return getattr(o, 'rule_%d' % i)
rules = tuple(get_rule(i) for i in xrange(3))
assert o.rules == rules
- def test_validation(self):
- """
- Test the validation method.
- """
- o = self.sub()()
- o.validate(9)
- for i in xrange(3):
- e = raises(errors.RuleError, o.validate, i)
- assert e.error == 'cannot be %d' % i
- assert e.value == i
+ def test_default(self):
+ assert 'default' in self.cls.__public__
+ assert self.cls().default() is None
+
+