summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/plugable.py33
-rw-r--r--ipalib/tests/test_plugable.py88
2 files changed, 121 insertions, 0 deletions
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
index 45c73354..0d8286a4 100644
--- a/ipalib/plugable.py
+++ b/ipalib/plugable.py
@@ -122,6 +122,39 @@ def lock(readonly):
return readonly
+class SetProxy(ReadOnly):
+ def __init__(self, s):
+ allowed = (set, frozenset, dict)
+ if type(s) not in allowed:
+ raise TypeError('%r not in %r' % (type(s), allowed))
+ self.__s = s
+ lock(self)
+
+ def __len__(self):
+ return len(self.__s)
+
+ def __iter__(self):
+ for key in sorted(self.__s):
+ yield key
+
+ def __contains__(self, key):
+ return key in self.__s
+
+
+class DictProxy(SetProxy):
+ def __init__(self, d):
+ if type(d) is not dict:
+ raise TypeError('%r is not %r' % (type(d), dict))
+ self.__d = d
+ super(DictProxy, self).__init__(d)
+
+ def __getitem__(self, key):
+ """
+ Returns the value
+ """
+ return self.__d[key]
+
+
class Plugin(ReadOnly):
"""
Base class for all plugins.
diff --git a/ipalib/tests/test_plugable.py b/ipalib/tests/test_plugable.py
index ba665447..0410bf31 100644
--- a/ipalib/tests/test_plugable.py
+++ b/ipalib/tests/test_plugable.py
@@ -117,6 +117,94 @@ def test_lock():
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 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)
+
+ # Verify TypeError is raised trying to set/del via proxy
+ raises(TypeError, setitem, proxy, key, val)
+ raises(TypeError, delitem, proxy, key)
+
+
class test_Plugin(ClassChecker):
"""
Tests the `plugable.Plugin` class.