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
 class LeFactory(object):
13
 class LeFactory(object):
14
     
14
     
15
     output_file = 'dyn.py'
15
     output_file = 'dyn.py'
16
+    modname = None
16
 
17
 
17
     def __init__(LeFactory):raise NotImplementedError("Not designed (yet?) to be implemented")
18
     def __init__(LeFactory):raise NotImplementedError("Not designed (yet?) to be implemented")
18
 
19
 
20
     # @return a python class or False
21
     # @return a python class or False
21
     @staticmethod
22
     @staticmethod
22
     def leobj_from_name(name):
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
         try:
29
         try:
25
             res = getattr(mod, name)
30
             res = getattr(mod, name)
26
         except AttributeError:
31
         except AttributeError:
184
             result += LeFactory.emtype_pycode(model, emtype)
189
             result += LeFactory.emtype_pycode(model, emtype)
185
 
190
 
186
         #Populating LeObject._me_uid dict for a rapid fetch of LeType and LeClass given an EM uid
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
         result += """
193
         result += """
188
 ## @brief Dict for getting LeClass and LeType child classes given an EM uid
194
 ## @brief Dict for getting LeClass and LeType child classes given an EM uid
189
 LeObject._me_uid = %s
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
         return result
197
         return result
193
 
198
 

+ 17
- 12
leobject/leobject.py View File

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

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

5
 import unittest
5
 import unittest
6
 from unittest import TestCase
6
 from unittest import TestCase
7
 
7
 
8
+import EditorialModel
9
+import leobject
10
+import leobject.test.utils
8
 from leobject.leobject import _LeObject
11
 from leobject.leobject import _LeObject
9
 
12
 
13
+## Testing static methods that don't need the generated code
10
 class _LeObjectTestCase(TestCase):
14
 class _LeObjectTestCase(TestCase):
11
     
15
     
12
     def test_split_query_filter(self):
16
     def test_split_query_filter(self):
47
         for query in invalid_queries:
51
         for query in invalid_queries:
48
             with self.assertRaises(ValueError, msg='But the query was not valid : "%s"'%query):
52
             with self.assertRaises(ValueError, msg='But the query was not valid : "%s"'%query):
49
                 _LeObject._split_filter(query)
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