[selectors] multi_lines_rset selector supports now optional operator for richer comparaisons stable
authorJulien Jehannet <julien.jehannet@logilab.fr>
Fri, 24 Sep 2010 13:41:13 +0200
branchstable
changeset 6348 f5bd501628b0
parent 6347 ef47a2100c66
child 6349 14ec625b3f55
[selectors] multi_lines_rset selector supports now optional operator for richer comparaisons
selectors.py
test/unittest_selectors.py
--- a/selectors.py	Fri Sep 24 15:00:08 2010 +0200
+++ b/selectors.py	Fri Sep 24 13:41:13 2010 +0200
@@ -194,6 +194,7 @@
 
 import logging
 from warnings import warn
+from operator import eq
 
 from logilab.common.deprecation import class_renamed
 from logilab.common.compat import all, any
@@ -530,17 +531,26 @@
 
 
 class multi_lines_rset(Selector):
-    """If `nb` is specified, return 1 if the result set has exactly `nb` row of
-    result. Else (`nb` is None), return 1 if the result set contains *at least*
+    """Return 1 if the operator expression matches between `num` elements
+    in the result set and the `expected` value if defined.
+    
+    By default, multi_lines_rset(expected) matches equality expression:
+        `nb` row(s) in result set equals to expected value
+    But, you can perform richer comparisons by overriding default operator:
+        multi_lines_rset(expected, operator.gt)
+    
+    If `expected` is None, return 1 if the result set contains *at least*
     two rows.
+    If rset is None, return 0.
     """
-    def __init__(self, nb=None):
-        self.expected = nb
+    def __init__(self, expected=None, operator=eq):
+        self.expected = expected
+        self.operator = operator
 
     def match_expected(self, num):
         if self.expected is None:
             return num > 1
-        return num == self.expected
+        return self.operator(num, self.expected)
 
     @lltrace
     def __call__(self, cls, req, rset=None, **kwargs):
--- a/test/unittest_selectors.py	Fri Sep 24 15:00:08 2010 +0200
+++ b/test/unittest_selectors.py	Fri Sep 24 13:41:13 2010 +0200
@@ -17,12 +17,14 @@
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 """unit tests for selectors mechanism"""
 
+from operator import eq, lt, le, gt
 from logilab.common.testlib import TestCase, unittest_main
 
 from cubicweb import Binary
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.appobject import Selector, AndSelector, OrSelector
-from cubicweb.selectors import is_instance, adaptable, match_user_groups
+from cubicweb.selectors import (is_instance, adaptable, match_user_groups,
+                                multi_lines_rset)
 from cubicweb.interfaces import IDownloadable
 from cubicweb.web import action
 
@@ -190,6 +192,59 @@
         finally:
             del self.vreg[SomeAction.__registry__][SomeAction.__regid__]
 
+
+class MultiLinesRsetSelectorTC(CubicWebTC):
+    def setUp(self):
+        super(MultiLinesRsetSelectorTC, self).setUp()
+        self.req = self.request()
+        self.req.execute('INSERT CWGroup G: G name "group1"')
+        self.req.execute('INSERT CWGroup G: G name "group2"')
+        self.commit()
+        self.rset = self.req.execute('Any G WHERE G is CWGroup')
+
+    def test_default_op_in_selector(self):
+        expected = len(self.rset)
+        selector = multi_lines_rset(expected)
+        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, None), 0)
+        selector = multi_lines_rset(expected + 1)
+        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, None), 0)
+        selector = multi_lines_rset(expected - 1)
+        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, None), 0)
+
+    def test_without_rset(self):
+        expected = len(self.rset)
+        selector = multi_lines_rset(expected)
+        self.assertEqual(selector(None, self.req, None), 0)
+        selector = multi_lines_rset(expected + 1)
+        self.assertEqual(selector(None, self.req, None), 0)
+        selector = multi_lines_rset(expected - 1)
+        self.assertEqual(selector(None, self.req, None), 0)
+
+    def test_with_operators(self):
+        expected = len(self.rset)
+
+        # Format     'expected', 'operator', 'assert'
+        testdata = (( expected,         eq,        1),
+                    ( expected+1,       eq,        0),
+                    ( expected-1,       eq,        0),
+                    ( expected,         le,        1),
+                    ( expected+1,       le,        1),
+                    ( expected-1,       le,        0),
+                    ( expected-1,       gt,        1),
+                    ( expected,         gt,        0),
+                    ( expected+1,       gt,        0),
+                    ( expected+1,       lt,        1),
+                    ( expected,         lt,        0),
+                    ( expected-1,       lt,        0))
+
+        for (expected, operator, assertion) in testdata:
+            selector = multi_lines_rset(expected, operator)
+            yield self.assertEqual, selector(None, self.req, self.rset), assertion
+
+
 if __name__ == '__main__':
     unittest_main()