Browse Source

Add tests for LeObject + bufix

Yann Weber 9 years ago
parent
commit
1d29e95951
3 changed files with 180 additions and 15 deletions
  1. 8
    3
      leobject/lefactory.py
  2. 17
    12
      leobject/leobject.py
  3. 155
    0
      leobject/test/test_leobject.py

+ 8
- 3
leobject/lefactory.py View File

@@ -13,6 +13,7 @@ from EditorialModel.fieldtypes.generic import GenericFieldType
13 13
 class LeFactory(object):
14 14
     
15 15
     output_file = 'dyn.py'
16
+    modname = None
16 17
 
17 18
     def __init__(LeFactory):raise NotImplementedError("Not designed (yet?) to be implemented")
18 19
 
@@ -20,7 +21,11 @@ class LeFactory(object):
20 21
     # @return a python class or False
21 22
     @staticmethod
22 23
     def leobj_from_name(name):
23
-        mod = importlib.import_module('leobject.'+LeFactory.output_file.split('.')[-1])
24
+        if LeFactory.modname is None:
25
+            modname = 'leobject.'+LeFactory.output_file.split('.')[1]
26
+        else:
27
+            modname = LeFactory.modname
28
+        mod = importlib.import_module(modname)
24 29
         try:
25 30
             res = getattr(mod, name)
26 31
         except AttributeError:
@@ -184,10 +189,10 @@ class {name}({leclass},LeType):
184 189
             result += LeFactory.emtype_pycode(model, emtype)
185 190
 
186 191
         #Populating LeObject._me_uid dict for a rapid fetch of LeType and LeClass given an EM uid
192
+        me_uid = { comp.uid:LeFactory.name2classname(comp.name) for comp in emclass_l + emtype_l }
187 193
         result += """
188 194
 ## @brief Dict for getting LeClass and LeType child classes given an EM uid
189 195
 LeObject._me_uid = %s
190
-"""%repr({ comp.uid:LeFactory.name2classname(comp.name) for comp in emclass_l + emtype_l })
191
-            
196
+"""%"{"+(','.join([ '%s:%s'%(k,v) for k,v in me_uid.items()]))+"}"       
192 197
         return result
193 198
 

+ 17
- 12
leobject/leobject.py View File

@@ -11,6 +11,9 @@
11 11
 # @note LeObject will be generated by leobject.lefactory.LeFactory
12 12
 
13 13
 import re
14
+
15
+import leobject
16
+import EditorialModel
14 17
 from EditorialModel.types import EmType
15 18
 
16 19
 ## @brief Main class to handle objects defined by the types of an Editorial Model
@@ -34,6 +37,7 @@ class _LeObject(object):
34 37
     ## @brief Given a ME uid return the corresponding LeClass or LeType class
35 38
     # @return a LeType or LeClass child class
36 39
     # @throw KeyError if no corresponding child classes
40
+    @classmethod
37 41
     def uid2leobj(cls, uid):
38 42
         uid = int(uid)
39 43
         if uid not in cls._me_uid:
@@ -134,21 +138,21 @@ class _LeObject(object):
134 138
         if not(leclass is None):
135 139
             if isinstance(leclass, str):
136 140
                 leclass = leobject.lefactory.LeFactory.leobj_from_name(leclass)
137
-
138
-            if not isinstance(leclass, LeClass) or leclass.__class__ == leobject.leclass.LeClass:
139
-                raise ValueError("None | str | LeType child class excpected, but got : %s"%type(letype))
141
+            
142
+            if not isinstance(leclass, type) or not (leobject.leclass.LeClass in leclass.__bases__) or leclass.__class__ == leobject.leclass.LeClass:
143
+                raise ValueError("None | str | LeType child class excpected, but got : '%s' %s"%(leclass,type(leclass)))
140 144
 
141 145
         if not(letype is None):
142 146
             if isinstance(letype, str):
143 147
                 letype = leobject.lefactory.LeFactory.leobj_from_name(letype)
144 148
 
145
-            if not isinstance(letype, LeType) or letype.__class__ == leobject.letype.LeType:
149
+            if not isinstance(letype, type) or not leobject.letype.LeType in letype.__bases__ or letype.__class__ == leobject.letype.LeType:
146 150
                 raise ValueError("None | str | LeType child class excpected, but got : %s"%type(letype))
147 151
 
148 152
             if leclass is None:
149 153
                 leclass = letype._leclass
150 154
             elif leclass != letype._leclass:
151
-                raise ValueError("LeType child class %s does'nt inherite from LeClass %s"%(letype.__name__, leclass.__name))
155
+                raise ValueError("LeType child class %s does'nt inherite from LeClass %s"%(letype.__name__, leclass.__name__))
152 156
 
153 157
         return (letype, leclass)
154 158
 
@@ -158,13 +162,14 @@ class _LeObject(object):
158 162
     # @param fields list : List of string representing fields
159 163
     # @throw LeObjectQueryError if their is some problems
160 164
     # @throw AttributeError if letype is not from the leclass class
165
+    # @todo Delete the checks of letype and leclass and ensure that this method is called with letype and leclass arguments from _prepare_targets()
161 166
     @staticmethod
162 167
     def _check_fields(letype, leclass, fields):
163 168
         #Checking that fields in the query_filters are correct
164 169
         if letype is None and leclass is None:
165 170
             #Only fields from the object table are allowed
166 171
             for field in fields:
167
-                if field not in EditorialModel.classtype.common_fields.keys():
172
+                if field not in EditorialModel.classtypes.common_fields.keys():
168 173
                     raise LeObjectQueryError("Not typename and no classname given, but the field %s is not in the common_fields list"%field)
169 174
         else:
170 175
             if letype is None:
@@ -176,7 +181,7 @@ class _LeObject(object):
176 181
                 field_l = letype._fields
177 182
             #Checks that fields are in this type
178 183
             for field in fields:
179
-                if field not in fields_l:
184
+                if field not in field_l:
180 185
                     raise LeObjectQueryError("No field named '%s' in '%s'"%(field, typename))
181 186
         pass
182 187
 
@@ -203,12 +208,12 @@ class _LeObject(object):
203 208
                 filters.append(_LeObject._split_filter(fil))
204 209
 
205 210
         #Checking relational filters (for the moment fields like superior.NATURE)
206
-        relational_filters = [ (LeFactory._nature_from_relational_field(field), operator, value) for field, operator, value in filters if LeFactory._field_is_relational(field)]
207
-        filters = [f for f in filters if not self._field_is_relational(f[0])]
211
+        relational_filters = [ (_LeObject._nature_from_relational_field(field), operator, value) for field, operator, value in filters if _LeObject._field_is_relational(field)]
212
+        filters = [f for f in filters if not _LeObject._field_is_relational(f[0])]
208 213
         #Checking the rest of the fields
209
-        LeFactory._check_fields(letype, leclass, [ f[0] for f in filters ])
214
+        _LeObject._check_fields(letype, leclass, [ f[0] for f in filters ])
210 215
         
211
-        return (filters, relationnal_filters)
216
+        return (filters, relational_filters)
212 217
 
213 218
 
214 219
     ## @brief Check if a field is relational or not
@@ -216,7 +221,7 @@ class _LeObject(object):
216 221
     # @return True if the field is relational else False
217 222
     @staticmethod
218 223
     def _field_is_relational(field):
219
-        return field.startwith('superior.')
224
+        return field.startswith('superior.')
220 225
     
221 226
     ## @brief Check that a relational field is valid
222 227
     # @param field str : a relational field

+ 155
- 0
leobject/test/test_leobject.py View File

@@ -5,8 +5,12 @@
5 5
 import unittest
6 6
 from unittest import TestCase
7 7
 
8
+import EditorialModel
9
+import leobject
10
+import leobject.test.utils
8 11
 from leobject.leobject import _LeObject
9 12
 
13
+## Testing static methods that don't need the generated code
10 14
 class _LeObjectTestCase(TestCase):
11 15
     
12 16
     def test_split_query_filter(self):
@@ -47,3 +51,154 @@ class _LeObjectTestCase(TestCase):
47 51
         for query in invalid_queries:
48 52
             with self.assertRaises(ValueError, msg='But the query was not valid : "%s"'%query):
49 53
                 _LeObject._split_filter(query)
54
+
55
+## Testing methods that need the generated code
56
+# @todo mock the datasource to test the get, update, delete and insert methods
57
+class LeObjectTestCase(TestCase):
58
+
59
+    @classmethod
60
+    def setUpClass(cls):
61
+        """ Write the generated code in a temporary directory and import it """
62
+        cls.tmpdir = leobject.test.utils.tmp_load_factory_code()
63
+    @classmethod
64
+    def tearDownClass(cls):
65
+        """ Remove the temporary directory created at class setup """
66
+        leobject.test.utils.cleanup(cls.tmpdir)
67
+
68
+    def test_uid2leobj(self):
69
+        """ Testing _Leobject.uid2leobj() """
70
+        import dyncode
71
+        for i in dyncode.LeObject._me_uid.keys():
72
+            cls = dyncode.LeObject.uid2leobj(i)
73
+            if leobject.letype.LeType in cls.__bases__:
74
+                self.assertEqual(i, cls._type_id)
75
+            elif leobject.leclass.LeClass in cls.__bases__:
76
+                self.assertEqual(i, cls._class_id)
77
+            else:
78
+                self.fail("Bad value returned : '%s'"%cls)
79
+        i=10
80
+        while i in dyncode.LeObject._me_uid.keys():
81
+            i+=1
82
+        with self.assertRaises(KeyError):
83
+            dyncode.LeObject.uid2leobj(i)
84
+    
85
+    def test_prepare_targets(self):
86
+        """ Testing _prepare_targets() method """
87
+        from dyncode import Publication, Numero, LeObject
88
+
89
+        test_v = {
90
+            (None, None) : (None, None),
91
+
92
+            (Publication, Numero): (Publication, Numero),
93
+            (Publication, None): (Publication, None),
94
+            (None, Numero): (Publication, Numero),
95
+
96
+            (Publication,'Numero'): (Publication, Numero),
97
+            ('Publication', Numero): (Publication, Numero),
98
+
99
+            ('Publication', 'Numero'): (Publication, Numero),
100
+            ('Publication', None): (Publication, None),
101
+            (None, 'Numero'): (Publication, Numero),
102
+        }
103
+
104
+        for (leclass, letype), (rleclass, rletype) in test_v.items():
105
+            self.assertEqual((rletype,rleclass), LeObject._prepare_targets(letype, leclass))
106
+
107
+    def test_invalid_prepare_targets(self):
108
+        """ Testing _prepare_targets() method with invalid arguments """
109
+        from dyncode import Publication, Numero, LeObject, Personnes
110
+        
111
+        test_v = [
112
+            ('',''),
113
+            (Personnes, Numero),
114
+            (leobject.leclass.LeClass, Numero),
115
+            (Publication, leobject.letype.LeType),
116
+            ('foobar', Numero),
117
+            (Publication, 'foobar'),
118
+            (Numero, Numero),
119
+            (Publication, Publication),
120
+            (None, Publication),
121
+            ('foobar', 'foobar'),
122
+            (42,1337),
123
+            (type, Numero),
124
+            (LeObject, Numero),
125
+            (LeObject, LeObject),
126
+            (Publication, LeObject),
127
+        ]
128
+
129
+        for (leclass, letype) in test_v:
130
+            with self.assertRaises(ValueError):
131
+                LeObject._prepare_targets(letype, leclass)
132
+
133
+    def test_check_fields(self):
134
+        """ Testing the _check_fields() method """
135
+        from dyncode import Publication, Numero, LeObject, Personnes
136
+        
137
+        #Valid fields given
138
+        LeObject._check_fields(None, Publication, Publication._fieldtypes.keys())
139
+        LeObject._check_fields(Numero, None, Numero._fields)
140
+
141
+        #Specials fields
142
+        LeObject._check_fields(Numero, Publication,  ['lodel_id'])
143
+        #Common fields
144
+        LeObject._check_fields(None, None, EditorialModel.classtypes.common_fields.keys())
145
+
146
+        #Invalid fields
147
+        with self.assertRaises(leobject.leobject.LeObjectQueryError):
148
+            LeObject._check_fields(None, None, Numero._fields)
149
+
150
+    def test_prepare_filters(self):
151
+        """ Testing the _prepare_filters() method """
152
+        from dyncode import Publication, Numero, LeObject, Personnes
153
+        
154
+        #Simple filters
155
+        filters = [
156
+            'lodel_id = 1',
157
+            'superior.parent  > 2'
158
+        ]
159
+
160
+        filt, rfilt = LeObject._prepare_filters(filters, Numero, None)
161
+        self.assertEqual(filt, [('lodel_id', '=', '1')])
162
+        self.assertEqual(rfilt, [('parent', '>', '2')])
163
+        
164
+        #All fields, no relationnal and class given
165
+        filters = []
166
+        res_filt = []
167
+        for field in Numero._fields:
168
+            filters.append('%s=1'%field)
169
+            res_filt.append((field, '=', '1'))
170
+
171
+        filt, rfilt = LeObject._prepare_filters(filters, None, Publication)
172
+        self.assertEqual(rfilt, [])
173
+        self.assertEqual(filt, res_filt)
174
+        
175
+        #Mixed type filters (tuple and string)
176
+        filters = [
177
+            ('lodel_id', '<=', '0'),
178
+            'superior.parent = 2',
179
+        ]
180
+        
181
+        filt, rfilt = LeObject._prepare_filters(filters, Numero, None)
182
+        self.assertEqual(filt, [('lodel_id', '<=', '0')])
183
+        self.assertEqual(rfilt, [('parent', '=', '2')])
184
+
185
+    def test_prepare_filters_invalid(self):
186
+        """ Testing the _prepare_filters() method """
187
+        from dyncode import Publication, Numero, LeObject, Personnes
188
+
189
+        #Numero fields filters but no letype nor leclass given
190
+        filters = []
191
+        res_filt = []
192
+        for field in Numero._fields:
193
+            filters.append('%s=1'%field)
194
+            res_filt.append((field, '=', '1'))
195
+        
196
+        with self.assertRaises(leobject.leobject.LeObjectQueryError):
197
+            LeObject._prepare_filters(filters, None, None)
198
+
199
+
200
+        #simply invalid filters
201
+        filters = ['hello world !']
202
+        with self.assertRaises(ValueError):
203
+            LeObject._prepare_filters(filters, None, None)
204
+    

Loading…
Cancel
Save