|
1 # -*- coding: utf-8 -*- |
|
2 """unit tests for cubicweb.entities.base module""" |
|
3 |
|
4 from mx.DateTime import now |
|
5 |
|
6 from logilab.common.testlib import unittest_main |
|
7 from logilab.common.decorators import clear_cache |
|
8 from logilab.common.interface import implements |
|
9 |
|
10 from cubicweb.devtools.apptest import EnvBasedTC |
|
11 |
|
12 from cubicweb import ValidationError |
|
13 from cubicweb.interfaces import IMileStone, IWorkflowable |
|
14 from cubicweb.entities import AnyEntity |
|
15 from cubicweb.entities.authobjs import EUser |
|
16 from cubicweb.web.widgets import AutoCompletionWidget |
|
17 |
|
18 |
|
19 class BaseEntityTC(EnvBasedTC): |
|
20 |
|
21 def setup_database(self): |
|
22 self.member = self.create_user('member') |
|
23 |
|
24 |
|
25 |
|
26 class MetadataTC(BaseEntityTC): |
|
27 |
|
28 def test_creator(self): |
|
29 self.login(u'member') |
|
30 card = self.add_entity('Card', title=u"hello") |
|
31 self.commit() |
|
32 self.assertEquals(card.creator.eid, self.member.eid) |
|
33 self.assertEquals(card.dc_creator(), u'member') |
|
34 |
|
35 def test_type(self): |
|
36 self.assertEquals(self.member.dc_type(), 'euser') |
|
37 |
|
38 def test_custom_widget(self): |
|
39 class EUser2(EUser): |
|
40 widgets = { |
|
41 'login' : 'AutoCompletionWidget', |
|
42 } |
|
43 clear_cache(self.vreg, 'etype_class') |
|
44 self.vreg.register_vobject_class(EUser2) |
|
45 p = self.entity('EUser U WHERE U login "member"') |
|
46 self.failUnless(isinstance(p, EUser2)) |
|
47 w = p.get_widget('login') |
|
48 self.failUnless(isinstance(w, AutoCompletionWidget)) |
|
49 |
|
50 def test_format_vocabulary(self): |
|
51 card = self.add_entity('Card', title=u"hello") |
|
52 self.assertEquals(card.default_content_format(), 'text/html') |
|
53 self.execute('INSERT EProperty X: X pkey "ui.default-text-format", X value "text/rest", X for_user U WHERE U login "admin"') |
|
54 self.commit() |
|
55 self.assertEquals(card.default_content_format(), 'text/rest') |
|
56 |
|
57 |
|
58 |
|
59 class EUserTC(BaseEntityTC): |
|
60 def test_dc_title_and_name(self): |
|
61 e = self.entity('EUser U WHERE U login "member"') |
|
62 self.assertEquals(e.dc_title(), 'member') |
|
63 self.assertEquals(e.name(), 'member') |
|
64 self.execute(u'SET X firstname "bouah" WHERE X is EUser, X login "member"') |
|
65 self.assertEquals(e.dc_title(), 'member') |
|
66 self.assertEquals(e.name(), u'bouah') |
|
67 self.execute(u'SET X surname "lôt" WHERE X is EUser, X login "member"') |
|
68 self.assertEquals(e.dc_title(), 'member') |
|
69 self.assertEquals(e.name(), u'bouah lôt') |
|
70 |
|
71 |
|
72 class StateAndTransitionsTC(BaseEntityTC): |
|
73 |
|
74 def test_transitions(self): |
|
75 user = self.entity('EUser X') |
|
76 e = self.entity('State S WHERE S name "activated"') |
|
77 trs = list(e.transitions(user)) |
|
78 self.assertEquals(len(trs), 1) |
|
79 self.assertEquals(trs[0].name, u'deactivate') |
|
80 self.assertEquals(trs[0].destination().name, u'deactivated') |
|
81 self.assert_(user.can_pass_transition('deactivate')) |
|
82 self.assert_(not user.can_pass_transition('activate')) |
|
83 # test a std user get no possible transition |
|
84 self.login('member') |
|
85 # fetch the entity using the new session |
|
86 e = self.entity('State S WHERE S name "activated"') |
|
87 trs = list(e.transitions(user)) |
|
88 self.assertEquals(len(trs), 0) |
|
89 user = self.entity('EUser X') |
|
90 self.assert_(not user.can_pass_transition('deactivate')) |
|
91 self.assert_(not user.can_pass_transition('activate')) |
|
92 |
|
93 def test_transitions_with_dest_specfied(self): |
|
94 user = self.entity('EUser X') |
|
95 e = self.entity('State S WHERE S name "activated"') |
|
96 e2 = self.entity('State S WHERE S name "deactivated"') |
|
97 trs = list(e.transitions(user, e2.eid)) |
|
98 self.assertEquals(len(trs), 1) |
|
99 self.assertEquals(trs[0].name, u'deactivate') |
|
100 self.assertEquals(trs[0].destination().name, u'deactivated') |
|
101 trs = list(e.transitions(user, e.eid)) |
|
102 self.assertEquals(len(trs), 0) |
|
103 |
|
104 def test_transitions_maybe_passed(self): |
|
105 self.execute('INSERT RQLExpression X: X exprtype "ERQLExpression", ' |
|
106 'X expression "X owned_by U", T condition X ' |
|
107 'WHERE T name "deactivate"') |
|
108 self._test_deactivated() |
|
109 |
|
110 def test_transitions_maybe_passed_using_has_update_perm(self): |
|
111 self.execute('INSERT RQLExpression X: X exprtype "ERQLExpression", ' |
|
112 'X expression "U has_update_permission X", T condition X ' |
|
113 'WHERE T name "deactivate"') |
|
114 self._test_deactivated() |
|
115 |
|
116 |
|
117 def _test_deactivated(self): |
|
118 ueid = self.create_user('toto').eid |
|
119 self.create_user('tutu') |
|
120 cnx = self.login('tutu') |
|
121 cu = cnx.cursor() |
|
122 self.assertRaises(ValidationError, |
|
123 cu.execute, 'SET X in_state S WHERE X eid %(x)s, S name "deactivated"', |
|
124 {'x': ueid}, 'x') |
|
125 cnx.close() |
|
126 cnx = self.login('toto') |
|
127 cu = cnx.cursor() |
|
128 cu.execute('SET X in_state S WHERE X eid %(x)s, S name "deactivated"', |
|
129 {'x': ueid}, 'x') |
|
130 cnx.commit() |
|
131 self.assertRaises(ValidationError, |
|
132 cu.execute, 'SET X in_state S WHERE X eid %(x)s, S name "activated"', |
|
133 {'x': ueid}, 'x') |
|
134 |
|
135 |
|
136 def test_transitions_selection(self): |
|
137 """ |
|
138 ------------------------ tr1 ----------------- |
|
139 | state1 (Card, Bookmark) | ------> | state2 (Card) | |
|
140 ------------------------ ----------------- |
|
141 | tr2 ------------------ |
|
142 `------> | state3 (Bookmark) | |
|
143 ------------------ |
|
144 """ |
|
145 state1 = self.add_entity('State', name=u'state1') |
|
146 state2 = self.add_entity('State', name=u'state2') |
|
147 state3 = self.add_entity('State', name=u'state3') |
|
148 tr1 = self.add_entity('Transition', name=u'tr1') |
|
149 tr2 = self.add_entity('Transition', name=u'tr2') |
|
150 self.execute('SET X state_of Y WHERE X eid in (%s, %s), Y is EEType, Y name "Card"' % |
|
151 (state1.eid, state2.eid)) |
|
152 self.execute('SET X state_of Y WHERE X eid in (%s, %s), Y is EEType, Y name "Bookmark"' % |
|
153 (state1.eid, state3.eid)) |
|
154 self.execute('SET X transition_of Y WHERE X eid %s, Y name "Card"' % tr1.eid) |
|
155 self.execute('SET X transition_of Y WHERE X eid %s, Y name "Bookmark"' % tr2.eid) |
|
156 self.execute('SET X allowed_transition Y WHERE X eid %s, Y eid %s' % |
|
157 (state1.eid, tr1.eid)) |
|
158 self.execute('SET X allowed_transition Y WHERE X eid %s, Y eid %s' % |
|
159 (state1.eid, tr2.eid)) |
|
160 self.execute('SET X destination_state Y WHERE X eid %s, Y eid %s' % |
|
161 (tr1.eid, state2.eid)) |
|
162 self.execute('SET X destination_state Y WHERE X eid %s, Y eid %s' % |
|
163 (tr2.eid, state3.eid)) |
|
164 self.execute('SET X initial_state Y WHERE Y eid %s, X name "Card"' % state1.eid) |
|
165 self.execute('SET X initial_state Y WHERE Y eid %s, X name "Bookmark"' % state1.eid) |
|
166 card = self.add_entity('Card', title=u't1') |
|
167 bookmark = self.add_entity('Bookmark', title=u'111', path=u'/view') |
|
168 |
|
169 transitions = list(state1.transitions(card)) |
|
170 self.assertEquals(len(transitions), 1) |
|
171 self.assertEquals(transitions[0].name, 'tr1') |
|
172 transitions = list(state1.transitions(bookmark)) |
|
173 self.assertEquals(len(transitions), 1) |
|
174 self.assertEquals(transitions[0].name, 'tr2') |
|
175 |
|
176 |
|
177 def test_transitions_selection2(self): |
|
178 """ |
|
179 ------------------------ tr1 (Bookmark) ----------------------- |
|
180 | state1 (Card, Bookmark) | -------------> | state2 (Card,Bookmark) | |
|
181 ------------------------ ----------------------- |
|
182 | tr2 (Card) | |
|
183 `---------------------------------/ |
|
184 """ |
|
185 state1 = self.add_entity('State', name=u'state1') |
|
186 state2 = self.add_entity('State', name=u'state2') |
|
187 tr1 = self.add_entity('Transition', name=u'tr1') |
|
188 tr2 = self.add_entity('Transition', name=u'tr2') |
|
189 self.execute('SET X state_of Y WHERE X eid in (%s, %s), Y is EEType, Y name "Card"' % |
|
190 (state1.eid, state2.eid)) |
|
191 self.execute('SET X state_of Y WHERE X eid in (%s, %s), Y is EEType, Y name "Bookmark"' % |
|
192 (state1.eid, state2.eid)) |
|
193 self.execute('SET X transition_of Y WHERE X eid %s, Y name "Card"' % tr1.eid) |
|
194 self.execute('SET X transition_of Y WHERE X eid %s, Y name "Bookmark"' % tr2.eid) |
|
195 self.execute('SET X allowed_transition Y WHERE X eid %s, Y eid %s' % |
|
196 (state1.eid, tr1.eid)) |
|
197 self.execute('SET X allowed_transition Y WHERE X eid %s, Y eid %s' % |
|
198 (state1.eid, tr2.eid)) |
|
199 self.execute('SET X destination_state Y WHERE X eid %s, Y eid %s' % |
|
200 (tr1.eid, state2.eid)) |
|
201 self.execute('SET X destination_state Y WHERE X eid %s, Y eid %s' % |
|
202 (tr2.eid, state2.eid)) |
|
203 self.execute('SET X initial_state Y WHERE Y eid %s, X name "Card"' % state1.eid) |
|
204 self.execute('SET X initial_state Y WHERE Y eid %s, X name "Bookmark"' % state1.eid) |
|
205 card = self.add_entity('Card', title=u't1') |
|
206 bookmark = self.add_entity('Bookmark', title=u'111', path=u'/view') |
|
207 |
|
208 transitions = list(state1.transitions(card)) |
|
209 self.assertEquals(len(transitions), 1) |
|
210 self.assertEquals(transitions[0].name, 'tr1') |
|
211 transitions = list(state1.transitions(bookmark)) |
|
212 self.assertEquals(len(transitions), 1) |
|
213 self.assertEquals(transitions[0].name, 'tr2') |
|
214 |
|
215 |
|
216 class EmailAddressTC(BaseEntityTC): |
|
217 def test_canonical_form(self): |
|
218 eid1 = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"')[0][0] |
|
219 eid2 = self.execute('INSERT EmailAddress X: X address "maarten@philips.com", X canonical TRUE')[0][0] |
|
220 self.execute('SET X identical_to Y WHERE X eid %s, Y eid %s' % (eid1, eid2)) |
|
221 email1 = self.entity('Any X WHERE X eid %(x)s', {'x':eid1}, 'x') |
|
222 email2 = self.entity('Any X WHERE X eid %(x)s', {'x':eid2}, 'x') |
|
223 self.assertEquals(email1.canonical_form().eid, eid2) |
|
224 self.assertEquals(email2.canonical_form(), email2) |
|
225 eid3 = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr"')[0][0] |
|
226 email3 = self.entity('Any X WHERE X eid %s'%eid3) |
|
227 self.assertEquals(email3.canonical_form(), None) |
|
228 |
|
229 def test_mangling(self): |
|
230 eid = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"')[0][0] |
|
231 email = self.entity('Any X WHERE X eid %(x)s', {'x':eid}, 'x') |
|
232 self.assertEquals(email.display_address(), 'maarten.ter.huurne@philips.com') |
|
233 self.assertEquals(email.printable_value('address'), 'maarten.ter.huurne@philips.com') |
|
234 self.vreg.config.global_set_option('mangle-emails', True) |
|
235 self.assertEquals(email.display_address(), 'maarten.ter.huurne at philips dot com') |
|
236 self.assertEquals(email.printable_value('address'), 'maarten.ter.huurne at philips dot com') |
|
237 eid = self.execute('INSERT EmailAddress X: X address "syt"')[0][0] |
|
238 email = self.entity('Any X WHERE X eid %(x)s', {'x':eid}, 'x') |
|
239 self.assertEquals(email.display_address(), 'syt') |
|
240 self.assertEquals(email.printable_value('address'), 'syt') |
|
241 |
|
242 |
|
243 class EUserTC(BaseEntityTC): |
|
244 |
|
245 def test_complete(self): |
|
246 e = self.entity('EUser X WHERE X login "admin"') |
|
247 e.complete() |
|
248 |
|
249 |
|
250 def test_matching_groups(self): |
|
251 e = self.entity('EUser X WHERE X login "admin"') |
|
252 self.failUnless(e.matching_groups('managers')) |
|
253 self.failIf(e.matching_groups('xyz')) |
|
254 self.failUnless(e.matching_groups(('xyz', 'managers'))) |
|
255 self.failIf(e.matching_groups(('xyz', 'abcd'))) |
|
256 |
|
257 def test_subject_in_state_vocabulary(self): |
|
258 # on a new entity |
|
259 e = self.etype_instance('EUser') |
|
260 rschema = e.e_schema.subject_relation('in_state') |
|
261 states = list(e.subject_in_state_vocabulary(rschema)) |
|
262 self.assertEquals(len(states), 1) |
|
263 self.assertEquals(states[0][0], u'activated') # list of (combobox view, state eid) |
|
264 # on an existant entity |
|
265 e = self.entity('Any X WHERE X is EUser') |
|
266 self.assertEquals(e.in_state[0].name, 'activated') |
|
267 states = list(e.subject_in_state_vocabulary(rschema)) |
|
268 self.assertEquals(len(states), 1) |
|
269 self.assertEquals(states[0][0], u'deactivated') # list of (combobox view, state eid) |
|
270 |
|
271 def test_workflow_base(self): |
|
272 e = self.create_user('toto') |
|
273 self.assertEquals(e.state, 'activated') |
|
274 activatedeid = self.execute('State X WHERE X name "activated"')[0][0] |
|
275 deactivatedeid = self.execute('State X WHERE X name "deactivated"')[0][0] |
|
276 e.change_state(deactivatedeid, u'deactivate 1') |
|
277 self.commit() |
|
278 e.change_state(activatedeid, u'activate 1') |
|
279 self.commit() |
|
280 e.change_state(deactivatedeid, u'deactivate 2') |
|
281 self.commit() |
|
282 # get a fresh user to avoid potential cache issues |
|
283 e = self.entity('EUser X WHERE X eid %s' % e.eid) |
|
284 self.assertEquals([tr.comment for tr in e.reverse_wf_info_for], |
|
285 [None, 'deactivate 1', 'activate 1', 'deactivate 2']) |
|
286 self.assertEquals(e.latest_trinfo().comment, 'deactivate 2') |
|
287 |
|
288 |
|
289 class InterfaceTC(EnvBasedTC): |
|
290 |
|
291 def test_nonregr_subclasses_and_mixins_interfaces(self): |
|
292 class MyUser(EUser): |
|
293 __implements__ = (IMileStone,) |
|
294 self.vreg.register_vobject_class(MyUser) |
|
295 self.failUnless(implements(EUser, IWorkflowable)) |
|
296 self.failUnless(implements(MyUser, IMileStone)) |
|
297 self.failUnless(implements(MyUser, IWorkflowable)) |
|
298 |
|
299 |
|
300 class SpecializedEntityClassesTC(EnvBasedTC): |
|
301 |
|
302 def select_eclass(self, etype): |
|
303 # clear selector cache |
|
304 clear_cache(self.vreg, 'etype_class') |
|
305 return self.vreg.etype_class(etype) |
|
306 |
|
307 def test_etype_class_selection_and_specialization(self): |
|
308 # no specific class for Subdivisions, the default one should be selected |
|
309 eclass = self.select_eclass('SubDivision') |
|
310 self.failUnless(eclass.__autogenerated__) |
|
311 #self.assertEquals(eclass.__bases__, (AnyEntity,)) |
|
312 # build class from most generic to most specific and make |
|
313 # sure the most specific is always selected |
|
314 for etype in ('Company', 'Division', 'SubDivision'): |
|
315 class Foo(AnyEntity): |
|
316 id = etype |
|
317 self.vreg.register_vobject_class(Foo) |
|
318 eclass = self.select_eclass('SubDivision') |
|
319 if etype == 'SubDivision': |
|
320 self.failUnless(eclass is Foo) |
|
321 else: |
|
322 self.failUnless(eclass.__autogenerated__) |
|
323 self.assertEquals(eclass.__bases__, (Foo,)) |
|
324 # check Division eclass is still selected for plain Division entities |
|
325 eclass = self.select_eclass('Division') |
|
326 self.assertEquals(eclass.id, 'Division') |
|
327 |
|
328 if __name__ == '__main__': |
|
329 unittest_main() |