Quellcode durchsuchen

Written some tests for filtered queries + query re modifications

- the re for filter spliting is modified to better handle operators
- added leading & trailing space to some operators
Yann Weber vor 8 Jahren
Ursprung
Commit
f402902b5b

BIN
examples/em_test.pickle Datei anzeigen


+ 6
- 5
lodel/leapi/query.py Datei anzeigen

@@ -98,10 +98,10 @@ class LeFilteredQuery(LeQuery):
98 98
                         '!=',
99 99
                         '<',
100 100
                         '>',
101
-                        'in',
102
-                        'not in',
103
-                        'like',
104
-                        'not like']
101
+                        ' in ',
102
+                        ' not in ',
103
+                        ' like ',
104
+                        ' not like ']
105 105
     
106 106
     ##@brief Regular expression to process filters
107 107
     _query_re = None
@@ -235,6 +235,7 @@ a relational field, but %s.%s was present in the filter"
235 235
         if not matches:
236 236
             raise ValueError("The query_filter '%s' seems to be invalid"%query_filter)
237 237
         result = (matches.group('field'), re.sub(r'\s', ' ', matches.group('operator'), count=0), matches.group('value').strip())
238
+        result = [r.strip() for r in result]
238 239
         for r in result:
239 240
             if len(r) == 0:
240 241
                 raise ValueError("The query_filter '%s' seems to be invalid"%query_filter)
@@ -248,7 +249,7 @@ a relational field, but %s.%s was present in the filter"
248 249
         for operator in cls._query_operators[1:]:
249 250
             op_re_piece += '|(%s)'%operator.replace(' ', '\s')
250 251
         op_re_piece += ')'
251
-        cls._query_re = re.compile('^\s*(?P<field>(((superior)|(subordinate))\.)?[a-z_][a-z0-9\-_]*)\s*'+op_re_piece+'\s*(?P<value>[^<>=!].*)\s*$', flags=re.IGNORECASE)
252
+        cls._query_re = re.compile('^\s*(?P<field>(((superior)|(subordinate))\.)?[a-z_][a-z0-9\-_]*)\s*'+op_re_piece+'\s*(?P<value>.*)\s*$', flags=re.IGNORECASE)
252 253
         pass
253 254
 
254 255
     @classmethod

+ 0
- 0
tests/leapi/query/__init__.py Datei anzeigen


+ 114
- 0
tests/leapi/query/test_filtere.py Datei anzeigen

@@ -0,0 +1,114 @@
1
+import unittest
2
+
3
+import tests.loader_utils
4
+from tests.leapi.query.utils import dyncode_module as dyncode
5
+
6
+from lodel.leapi.leobject import LeApiDataCheckError
7
+from lodel.leapi.query import LeDeleteQuery, LeUpdateQuery, LeGetQuery
8
+
9
+class LeGetQueryTestCase(unittest.TestCase):
10
+    
11
+    def test_init_default(self):
12
+        """ Testing GetQuery instanciation default values"""
13
+        tclass_list = [ dyncode.Object,
14
+                        dyncode.Entry,
15
+                        dyncode.Person,
16
+                        dyncode.Text,
17
+                        dyncode.Section,
18
+                        dyncode.Publication,
19
+                        dyncode.Text_Person,
20
+        ]
21
+        for tclass in tclass_list:
22
+            get_q = LeGetQuery(tclass, [])
23
+            qinfos = get_q.dump_infos()
24
+            self.assertEqual(   set(qinfos['field_list']),
25
+                                set(tclass.fieldnames(True)))
26
+            self.assertEqual(   qinfos['limit'],
27
+                                None)
28
+            self.assertEqual(   qinfos['offset'],
29
+                                0)
30
+            self.assertEqual(   qinfos['group'],
31
+                                None)
32
+            self.assertEqual(   qinfos['order'],
33
+                                None)
34
+            self.assertEqual(   qinfos['query_filter'],
35
+                                ([],[]))
36
+            self.assertEqual(   qinfos['target_class'],
37
+                                tclass)
38
+
39
+class LeFilteredQueryTestCase(unittest.TestCase):
40
+
41
+    q_classes = [ LeDeleteQuery, LeUpdateQuery, LeGetQuery ]
42
+
43
+    def test_filters(self):
44
+        """ Testing FilteredQuery filters handling """
45
+        test_datas = [  (   'lodel_id = 42',
46
+                            (   [('lodel_id','=','42')],
47
+                                [])),
48
+                        (   'lodel_id <= 42',
49
+                            (   [('lodel_id','<=','42')],
50
+                                [])),
51
+                        (   ['lodel_id <= 42'],
52
+                            (   [('lodel_id','<=','42')],
53
+                                [])),
54
+                        (   ('lodel_id <= 42',),
55
+                            (   [('lodel_id','<=','42')],
56
+                                [])),
57
+                        (   ['lodel_id <= 42','lodel_id >= 33'],
58
+                            (   [   ('lodel_id','<=','42'),
59
+                                    ('lodel_id', '>=','33')],
60
+                                [])),
61
+        ]
62
+        for q_class in self.q_classes:
63
+            for q_filter_arg, e_qfilter in test_datas:
64
+                get_q = q_class(dyncode.Publication, q_filter_arg)
65
+                self.assertEqual(   get_q.dump_infos()['query_filter'],
66
+                                    e_qfilter)
67
+
68
+    def test_invalid_filters(self):
69
+        """ Testing invalid filters detection """
70
+        invalid_filters = ( 'lodel_id',
71
+                            '',
72
+                            '"',
73
+                            "'",
74
+                            "not_exists != bar",
75
+                            "lodel_id # bar",
76
+                            "lodel_id ind 42,43",
77
+                            "lodel_id llike 42",
78
+                            ('lodel_id', '', '42'),
79
+        )
80
+        for invalid_filter in invalid_filters:
81
+            for q_class in self.q_classes:
82
+                with self.assertRaises( LeApiDataCheckError,
83
+                                        msg="for filter '%s'" % (invalid_filter,)):
84
+                    q_class(dyncode.Publication, invalid_filter)
85
+            
86
+        
87
+    def test_filters_operators(self):
88
+        """ Testing FilteredQuery filters operator recognition """
89
+        ops = [         '=',
90
+                        '<=',
91
+                        '>=',
92
+                        '!=',
93
+                        '<',
94
+                        '>',
95
+                        'in',
96
+                        'not in',
97
+                        'like',
98
+                        'not like']
99
+        values = (  '42',
100
+                    'not in',
101
+                    'in',
102
+                    'like',
103
+                    '=',
104
+                    '!=',
105
+                    "'",
106
+                    '"',
107
+                    '"hello world !"')
108
+        for q_class in self.q_classes:
109
+            for op in ops:
110
+                for v in values:
111
+                    get_q = q_class(    dyncode.Publication,
112
+                                        'lodel_id %s %s' % (op,v))
113
+                    self.assertEqual(   get_q.dump_infos()['query_filter'],
114
+                                        ([('lodel_id',op,v)],[]))

+ 26
- 0
tests/leapi/query/utils.py Datei anzeigen

@@ -0,0 +1,26 @@
1
+#
2
+# Importing this file trigger dynamic code generation & load
3
+#
4
+# To use dynamic code import utils.dyncode_module as dyncode
5
+
6
+import tempfile
7
+import os
8
+from importlib.machinery import SourceFileLoader
9
+
10
+from lodel.leapi.lefactory import dyncode_from_em
11
+from lodel.editorial_model.translator import picklefile
12
+
13
+def init_dyncode():
14
+    f_handler, dyncode_file = tempfile.mkstemp( prefix="lodel2_tests",
15
+                                            suffix="_dyncode")
16
+    os.close(f_handler)
17
+    model = picklefile.load('tests/editorial_model.pickle')
18
+    source_code = dyncode_from_em(model)
19
+    with os.fdopen(os.open(dyncode_file, os.O_WRONLY), 'w') as dynfd:
20
+        dynfd.write(source_code)
21
+    dyncode_module = SourceFileLoader("lodel.dyncode", dyncode_file).load_module()
22
+    os.unlink(dyncode_file)
23
+    return dyncode_module
24
+
25
+dyncode_module = init_dyncode()
26
+

Laden…
Abbrechen
Speichern