unittest_views_basecontrollers.py 42.7 KB
Newer Older
1
# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2
3
4
5
6
7
8
9
10
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
#
# CubicWeb is free software: you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option)
# any later version.
#
11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
12
13
14
15
16
17
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
18
"""cubicweb.web.views.basecontrollers unit tests"""
Adrien Di Mascio's avatar
Adrien Di Mascio committed
19

20
21
22
23
24
25
from urlparse import urlsplit, urlunsplit, urljoin
# parse_qs is deprecated in cgi and has been moved to urlparse in Python 2.6
try:
    from urlparse import parse_qs as url_parse_query
except ImportError:
    from cgi import parse_qs as url_parse_query
26
from logilab.common.testlib import unittest_main, mock_object
27
from logilab.common.decorators import monkeypatch
Adrien Di Mascio's avatar
Adrien Di Mascio committed
28

29
30
from cubicweb import Binary, NoSelectableObject, ValidationError
from cubicweb.view import STRICT_DOCTYPE
31
from cubicweb.devtools.testlib import CubicWebTC
32
from cubicweb.utils import json_dumps
Sylvain Thénault's avatar
Sylvain Thénault committed
33
from cubicweb.uilib import rql_for_eid
34
from cubicweb.web import INTERNAL_FIELD_VALUE, Redirect, RequestError, RemoteCallFailed
35
36
import cubicweb.server.session
from cubicweb.server.session import Transaction as OldTransaction
37
from cubicweb.entities.authobjs import CWUser
Sylvain Thénault's avatar
Sylvain Thénault committed
38
from cubicweb.web.views.autoform import get_pending_inserts, get_pending_deletes
39
40
from cubicweb.web.views.basecontrollers import JSonController, xhtmlize, jsonize
from cubicweb.web.views.ajaxcontroller import ajaxfunc, AjaxFunction
41
import cubicweb.transaction as tx
42
43
from cubicweb.server.hook import Hook, Operation
from cubicweb.predicates import is_instance
44

Sylvain Thénault's avatar
Sylvain Thénault committed
45
46
u = unicode

Sylvain Thénault's avatar
Sylvain Thénault committed
47
48
def req_form(user):
    return {'eid': [str(user.eid)],
49
            '_cw_entity_fields:%s' % user.eid: '_cw_generic_field',
Sylvain Thénault's avatar
Sylvain Thénault committed
50
51
            '__type:%s' % user.eid: user.__regid__
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
52

53
class EditControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
54
    def setUp(self):
55
        CubicWebTC.setUp(self)
56
        self.assertTrue('users' in self.schema.eschema('CWGroup').get_groups('read'))
57

Adrien Di Mascio's avatar
Adrien Di Mascio committed
58
    def tearDown(self):
59
        CubicWebTC.tearDown(self)
60
        self.assertTrue('users' in self.schema.eschema('CWGroup').get_groups('read'))
61

Adrien Di Mascio's avatar
Adrien Di Mascio committed
62
63
64
    def test_noparam_edit(self):
        """check behaviour of this controller without any form parameter
        """
65
66
67
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(self.request())
        self.assertEqual(cm.exception.errors, {None: u'no selected entities'})
68

Adrien Di Mascio's avatar
Adrien Di Mascio committed
69
70
    def test_validation_unique(self):
        """test creation of two linked entities
71
        """
Adrien Di Mascio's avatar
Adrien Di Mascio committed
72
        user = self.user()
73
74
        req = self.request()
        req.form = {'eid': 'X', '__type:X': 'CWUser',
75
                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
76
77
78
                    'login-subject:X': u'admin',
                    'upassword-subject:X': u'toto',
                    'upassword-subject-confirm:X': u'toto',
79
                    }
80
81
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
82
        cm.exception.translate(unicode)
83
        self.assertEqual(cm.exception.errors, {'login-subject': 'the value "admin" is already used, use another one'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
84
85
86
87
88

    def test_user_editing_itself(self):
        """checking that a manager user can edit itself
        """
        user = self.user()
Sylvain Thénault's avatar
Sylvain Thénault committed
89
        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X in_group G, X eid %(x)s', {'x': user.eid})]
90
        groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')]
Sylvain Thénault's avatar
Sylvain Thénault committed
91
        groups = [u(eid) for eid in groupeids]
92
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
93
        eid = u(user.eid)
94
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
95
            'eid': eid, '__type:'+eid: 'CWUser',
96
            '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
97
98
99
100
            'login-subject:'+eid:     u(user.login),
            'surname-subject:'+eid: u'Th\xe9nault',
            'firstname-subject:'+eid:   u'Sylvain',
            'in_group-subject:'+eid:  groups,
Adrien Di Mascio's avatar
Adrien Di Mascio committed
101
            }
102
        path, params = self.expect_redirect_handle_request(req, 'edit')
103
        e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0)
104
105
106
107
        self.assertEqual(e.firstname, u'Sylvain')
        self.assertEqual(e.surname, u'Th\xe9nault')
        self.assertEqual(e.login, user.login)
        self.assertEqual([g.eid for g in e.in_group], groupeids)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
108
109
110

    def test_user_can_change_its_password(self):
        req = self.request()
111
112
        user = self.create_user(req, 'user')
        cnx = self.login('user')
Sylvain Thénault's avatar
Sylvain Thénault committed
113
        eid = u(user.eid)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
114
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
115
116
            'eid': eid, '__maineid' : eid,
            '__type:'+eid: 'CWUser',
117
            '_cw_entity_fields:'+eid: 'upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
118
119
            'upassword-subject:'+eid: 'tournicoton',
            'upassword-subject-confirm:'+eid: 'tournicoton',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
120
            }
121
        path, params = self.expect_redirect_handle_request(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
122
        cnx.commit() # commit to check we don't get late validation error for instance
123
        self.assertEqual(path, 'cwuser/user')
124
        self.assertFalse('vid' in params)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
125

Sylvain Thénault's avatar
Sylvain Thénault committed
126
    def test_user_editing_itself_no_relation(self):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
127
128
129
130
        """checking we can edit an entity without specifying some required
        relations (meaning no changes)
        """
        user = self.user()
Sylvain Thénault's avatar
Sylvain Thénault committed
131
        groupeids = [g.eid for g in user.in_group]
132
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
133
        eid = u(user.eid)
134
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
135
136
            'eid':       eid,
            '__type:'+eid:    'CWUser',
137
            '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
138
139
140
            'login-subject:'+eid:     u(user.login),
            'firstname-subject:'+eid: u'Th\xe9nault',
            'surname-subject:'+eid:   u'Sylvain',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
141
            }
142
        path, params = self.expect_redirect_handle_request(req, 'edit')
143
        e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0)
144
145
146
147
148
        self.assertEqual(e.login, user.login)
        self.assertEqual(e.firstname, u'Th\xe9nault')
        self.assertEqual(e.surname, u'Sylvain')
        self.assertEqual([g.eid for g in e.in_group], groupeids)
        self.assertEqual(e.cw_adapt_to('IWorkflowable').state, 'activated')
149
150


Adrien Di Mascio's avatar
Adrien Di Mascio committed
151
    def test_create_multiple_linked(self):
152
        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
153
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
154
        req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
155

156
                    '__type:X': 'CWUser',
157
                    '_cw_entity_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
158
159
160
161
                    'login-subject:X': u'adim',
                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
                    'surname-subject:X': u'Di Mascio',
                    'in_group-subject:X': u(gueid),
162

163
                    '__type:Y': 'EmailAddress',
164
                    '_cw_entity_fields:Y': 'address-subject,use_email-object',
Sylvain Thénault's avatar
Sylvain Thénault committed
165
166
                    'address-subject:Y': u'dima@logilab.fr',
                    'use_email-object:Y': 'X',
167
                    }
168
        path, params = self.expect_redirect_handle_request(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
169
        # should be redirected on the created person
170
        self.assertEqual(path, 'cwuser/adim')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
171
        e = self.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0)
172
        self.assertEqual(e.surname, 'Di Mascio')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
173
        email = e.use_email[0]
174
        self.assertEqual(email.address, 'dima@logilab.fr')
175

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    def test_create_mandatory_inlined(self):
        req = self.request()
        req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',

                    '__type:X': 'Salesterm',
                    '_cw_entity_fields:X': '',

                    '__type:Y': 'File',
                    '_cw_entity_fields:Y': 'data-subject,described_by_test-object',
                    'data-subject:Y': (u'coucou.txt', Binary('coucou')),
                    'described_by_test-object:Y': 'X',
                    }
        path, params = self.expect_redirect_handle_request(req, 'edit')
        self.assertTrue(path.startswith('salesterm/'), path)
        eid = path.split('/')[1]
        salesterm = req.entity_from_eid(eid)
        # The NOT NULL constraint of mandatory relation implies that the File
        # must be created before the Salesterm, otherwise Salesterm insertion
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
        # will fail.
        # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
        # insertion does not fail and we have to check dumbly that File is
        # created before.
        self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)

    def test_create_mandatory_inlined2(self):
        req = self.request()
        req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',

                    '__type:X': 'Salesterm',
                    '_cw_entity_fields:X': 'described_by_test-subject',
                    'described_by_test-subject:X': 'Y',

                    '__type:Y': 'File',
                    '_cw_entity_fields:Y': 'data-subject',
                    'data-subject:Y': (u'coucou.txt', Binary('coucou')),
                    }
        path, params = self.expect_redirect_handle_request(req, 'edit')
        self.assertTrue(path.startswith('salesterm/'), path)
        eid = path.split('/')[1]
        salesterm = req.entity_from_eid(eid)
        # The NOT NULL constraint of mandatory relation implies that the File
        # must be created before the Salesterm, otherwise Salesterm insertion
218
219
220
221
222
223
        # will fail.
        # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
        # insertion does not fail and we have to check dumbly that File is
        # created before.
        self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)

Adrien Di Mascio's avatar
Adrien Di Mascio committed
224
    def test_edit_multiple_linked(self):
225
        req = self.request()
226
        peid = u(self.create_user(req, 'adim').eid)
Sylvain Thénault's avatar
Sylvain Thénault committed
227
        req.form = {'eid': [peid, 'Y'], '__maineid': peid,
228

Sylvain Thénault's avatar
Sylvain Thénault committed
229
                    '__type:'+peid: u'CWUser',
230
                    '_cw_entity_fields:'+peid: u'surname-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
231
                    'surname-subject:'+peid: u'Di Masci',
232

Sylvain Thénault's avatar
Sylvain Thénault committed
233
                    '__type:Y': u'EmailAddress',
234
                    '_cw_entity_fields:Y': u'address-subject,use_email-object',
Sylvain Thénault's avatar
Sylvain Thénault committed
235
236
                    'address-subject:Y': u'dima@logilab.fr',
                    'use_email-object:Y': peid,
237
                    }
238
        path, params = self.expect_redirect_handle_request(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
239
        # should be redirected on the created person
240
        self.assertEqual(path, 'cwuser/adim')
Sylvain Thénault's avatar
Sylvain Thénault committed
241
        e = self.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
242
        email = e.use_email[0]
243
        self.assertEqual(email.address, 'dima@logilab.fr')
244

Sylvain Thénault's avatar
Sylvain Thénault committed
245
        emaileid = u(email.eid)
246
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
247
248
249
        req.form = {'eid': [peid, emaileid],

                    '__type:'+peid: u'CWUser',
250
                    '_cw_entity_fields:'+peid: u'surname-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
251
252
253
                    'surname-subject:'+peid: u'Di Masci',

                    '__type:'+emaileid: u'EmailAddress',
254
                    '_cw_entity_fields:'+emaileid: u'address-subject,use_email-object',
Sylvain Thénault's avatar
Sylvain Thénault committed
255
256
257
                    'address-subject:'+emaileid: u'adim@logilab.fr',
                    'use_email-object:'+emaileid: peid,
                    }
258
        path, params = self.expect_redirect_handle_request(req, 'edit')
259
        email.cw_clear_all_caches()
260
        self.assertEqual(email.address, 'adim@logilab.fr')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
261

262

Adrien Di Mascio's avatar
Adrien Di Mascio committed
263
264
    def test_password_confirm(self):
        """test creation of two linked entities
265
        """
Adrien Di Mascio's avatar
Adrien Di Mascio committed
266
        user = self.user()
267
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
268
269
        req.form = {'eid': 'X',
                    '__cloned_eid:X': u(user.eid), '__type:X': 'CWUser',
270
                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
271
272
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto',
273
                    }
274
275
276
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
        self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'})
277
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
278
        req.form = {'__cloned_eid:X': u(user.eid),
279
                    'eid': 'X', '__type:X': 'CWUser',
280
                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
281
282
283
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto',
                    'upassword-subject-confirm:X': u'tutu',
284
                    }
285
286
287
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
        self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
288
289
290


    def test_interval_bound_constraint_success(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
291
        feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
292
                            {'data': Binary('yo')})[0][0]
293
        self.commit()
294
        req = self.request(rollbackfirst=True)
295
296
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
297
                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
298
299
                    'amount-subject:X': u'-10',
                    'described_by_test-subject:X': u(feid),
300
                }
301
302
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
303
        cm.exception.translate(unicode)
304
        self.assertEqual(cm.exception.errors, {'amount-subject': 'value -10 must be >= 0'})
305
        req = self.request(rollbackfirst=True)
306
307
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
308
                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
309
310
                    'amount-subject:X': u'110',
                    'described_by_test-subject:X': u(feid),
311
                    }
312
313
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
314
        cm.exception.translate(unicode)
315
        self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'})
316

317
        req = self.request(rollbackfirst=True)
318
319
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
320
                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
321
322
                    'amount-subject:X': u'10',
                    'described_by_test-subject:X': u(feid),
323
                    }
324
        self.expect_redirect_handle_request(req, 'edit')
325
        # should be redirected on the created
Adrien Di Mascio's avatar
Adrien Di Mascio committed
326
327
        #eid = params['rql'].split()[-1]
        e = self.execute('Salesterm X').get_entity(0, 0)
328
        self.assertEqual(e.amount, 10)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
329

330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
    def test_interval_bound_constraint_validateform(self):
        """Test the FormValidatorController controller on entity with
        constrained attributes"""
        feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
                            {'data': Binary('yo')})[0][0]
        seid = self.request().create_entity('Salesterm', amount=0, described_by_test=feid).eid
        self.commit()

        # ensure a value that violate a constraint is properly detected
        req = self.request(rollbackfirst=True)
        req.form = {'eid': [unicode(seid)],
                    '__type:%s'%seid: 'Salesterm',
                    '_cw_entity_fields:%s'%seid: 'amount-subject',
                    'amount-subject:%s'%seid: u'-10',
                }
        self.assertEqual('''<script type="text/javascript">
 window.parent.handleFormValidationResponse('entityForm', null, null, [false, [%s, {"amount-subject": "value -10 must be >= 0"}], null], null);
</script>'''%seid, self.ctrl_publish(req, 'validateform'))

        # ensure a value that comply a constraint is properly processed
        req = self.request(rollbackfirst=True)
        req.form = {'eid': [unicode(seid)],
                    '__type:%s'%seid: 'Salesterm',
                    '_cw_entity_fields:%s'%seid: 'amount-subject',
                    'amount-subject:%s'%seid: u'20',
                }
        self.assertEqual('''<script type="text/javascript">
 window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
</script>''', self.ctrl_publish(req, 'validateform'))
        self.assertEqual(20, self.execute('Any V WHERE X amount V, X eid %(eid)s', {'eid': seid})[0][0])

        req = self.request(rollbackfirst=True)
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
                    'amount-subject:X': u'0',
                    'described_by_test-subject:X': u(feid),
                }

        # ensure a value that is modified in an operation on a modify
        # hook works as it should (see
        # https://www.cubicweb.org/ticket/2509729 )
        class MyOperation(Operation):
            def precommit_event(self):
                self.entity.cw_set(amount=-10)
        class ValidationErrorInOpAfterHook(Hook):
            __regid__ = 'valerror-op-after-hook'
            __select__ = Hook.__select__ & is_instance('Salesterm')
            events = ('after_add_entity',)
            def __call__(self):
                MyOperation(self._cw, entity=self.entity)

        with self.temporary_appobjects(ValidationErrorInOpAfterHook):
            self.assertEqual('''<script type="text/javascript">
 window.parent.handleFormValidationResponse('entityForm', null, null, [false, ["X", {"amount-subject": "value -10 must be >= 0"}], null], null);
</script>''', self.ctrl_publish(req, 'validateform'))

        self.assertEqual('''<script type="text/javascript">
 window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
</script>''', self.ctrl_publish(req, 'validateform'))

Adrien Di Mascio's avatar
Adrien Di Mascio committed
391
392
    def test_req_pending_insert(self):
        """make sure req's pending insertions are taken into account"""
Sylvain Thénault's avatar
Sylvain Thénault committed
393
        tmpgroup = self.request().create_entity('CWGroup', name=u"test")
Adrien Di Mascio's avatar
Adrien Di Mascio committed
394
        user = self.user()
Sylvain Thénault's avatar
Sylvain Thénault committed
395
        req = self.request(**req_form(user))
396
        req.session.data['pending_insert'] = set([(user.eid, 'in_group', tmpgroup.eid)])
397
        path, params = self.expect_redirect_handle_request(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
398
399
        usergroups = [gname for gname, in
                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
400
401
        self.assertItemsEqual(usergroups, ['managers', 'test'])
        self.assertEqual(get_pending_inserts(req), [])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
402
403
404
405

    def test_req_pending_delete(self):
        """make sure req's pending deletions are taken into account"""
        user = self.user()
406
        groupeid = self.execute('INSERT CWGroup G: G name "test", U in_group G WHERE U eid %(x)s',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
407
408
409
410
                                {'x': user.eid})[0][0]
        usergroups = [gname for gname, in
                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
        # just make sure everything was set correctly
411
        self.assertItemsEqual(usergroups, ['managers', 'test'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
412
        # now try to delete the relation
Sylvain Thénault's avatar
Sylvain Thénault committed
413
        req = self.request(**req_form(user))
414
        req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)])
415
        path, params = self.expect_redirect_handle_request(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
416
417
        usergroups = [gname for gname, in
                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
418
419
        self.assertItemsEqual(usergroups, ['managers'])
        self.assertEqual(get_pending_deletes(req), [])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
420
421
422

    def test_redirect_apply_button(self):
        redirectrql = rql_for_eid(4012) # whatever
423
424
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
425
            'eid': 'A', '__maineid' : 'A',
426
            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
427
428
            'content-subject:A': u'"13:03:43"',
            'title-subject:A': u'huuu',
429
430
431
432
433
434
            '__redirectrql': redirectrql,
            '__redirectvid': 'primary',
            '__redirectparams': 'toto=tutu&tata=titi',
            '__form_id': 'edition',
            '__action_apply': '',
            }
435
        path, params = self.expect_redirect_handle_request(req, 'edit')
436
        self.assertTrue(path.startswith('blogentry/'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
437
        eid = path.split('/')[1]
438
        self.assertEqual(params['vid'], 'edition')
439
        self.assertNotEqual(int(eid), 4012)
440
441
442
        self.assertEqual(params['__redirectrql'], redirectrql)
        self.assertEqual(params['__redirectvid'], 'primary')
        self.assertEqual(params['__redirectparams'], 'toto=tutu&tata=titi')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
443
444
445

    def test_redirect_ok_button(self):
        redirectrql = rql_for_eid(4012) # whatever
446
447
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
448
            'eid': 'A', '__maineid' : 'A',
449
            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
450
451
            'content-subject:A': u'"13:03:43"',
            'title-subject:A': u'huuu',
452
453
454
455
456
            '__redirectrql': redirectrql,
            '__redirectvid': 'primary',
            '__redirectparams': 'toto=tutu&tata=titi',
            '__form_id': 'edition',
            }
457
        path, params = self.expect_redirect_handle_request(req, 'edit')
458
459
460
461
462
        self.assertEqual(path, 'view')
        self.assertEqual(params['rql'], redirectrql)
        self.assertEqual(params['vid'], 'primary')
        self.assertEqual(params['tata'], 'titi')
        self.assertEqual(params['toto'], 'tutu')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
463
464

    def test_redirect_delete_button(self):
465
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
466
        eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
Sylvain Thénault's avatar
Sylvain Thénault committed
467
        req.form = {'eid': u(eid), '__type:%s'%eid: 'BlogEntry',
468
                    '__action_delete': ''}
469
        path, params = self.expect_redirect_handle_request(req, 'edit')
470
        self.assertEqual(path, 'blogentry')
Sylvain Thénault's avatar
Sylvain Thénault committed
471
        self.assertIn('_cwmsgid', params)
Sylvain Thénault's avatar
Sylvain Thénault committed
472
        eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
Adrien Di Mascio's avatar
Adrien Di Mascio committed
473
        self.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s',
474
                     {'x': self.session.user.eid, 'e': eid})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
475
        self.commit()
Sylvain Thénault's avatar
Sylvain Thénault committed
476
        req = req
Sylvain Thénault's avatar
Sylvain Thénault committed
477
        req.form = {'eid': u(eid), '__type:%s'%eid: 'EmailAddress',
478
                    '__action_delete': ''}
479
        path, params = self.expect_redirect_handle_request(req, 'edit')
480
        self.assertEqual(path, 'cwuser/admin')
Sylvain Thénault's avatar
Sylvain Thénault committed
481
        self.assertIn('_cwmsgid', params)
Sylvain Thénault's avatar
Sylvain Thénault committed
482
483
        eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
        eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
484
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
485
        req.form = {'eid': [u(eid1), u(eid2)],
486
487
488
                    '__type:%s'%eid1: 'BlogEntry',
                    '__type:%s'%eid2: 'EmailAddress',
                    '__action_delete': ''}
489
        path, params = self.expect_redirect_handle_request(req, 'edit')
490
        self.assertEqual(path, 'view')
Sylvain Thénault's avatar
Sylvain Thénault committed
491
        self.assertIn('_cwmsgid', params)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
492

493
494
495
496
497
498
499
500
501
502
503
504
    def test_simple_copy(self):
        req = self.request()
        blog = req.create_entity('Blog', title=u'my-blog')
        blogentry = req.create_entity('BlogEntry', title=u'entry1',
                                      content=u'content1', entry_of=blog)
        req = self.request()
        req.form = {'__maineid' : 'X', 'eid': 'X',
                    '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
                    '_cw_entity_fields:X': 'title-subject,content-subject',
                    'title-subject:X': u'entry1-copy',
                    'content-subject:X': u'content1',
                    }
505
        self.expect_redirect_handle_request(req, 'edit')
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
        blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
        self.assertEqual(blogentry2.entry_of[0].eid, blog.eid)

    def test_skip_copy_for(self):
        req = self.request()
        blog = req.create_entity('Blog', title=u'my-blog')
        blogentry = req.create_entity('BlogEntry', title=u'entry1',
                                      content=u'content1', entry_of=blog)
        blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')]
        try:
            req = self.request()
            req.form = {'__maineid' : 'X', 'eid': 'X',
                        '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
                        '_cw_entity_fields:X': 'title-subject,content-subject',
                        'title-subject:X': u'entry1-copy',
                        'content-subject:X': u'content1',
                        }
523
            self.expect_redirect_handle_request(req, 'edit')
524
525
526
527
528
529
            blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
            # entry_of should not be copied
            self.assertEqual(len(blogentry2.entry_of), 0)
        finally:
            blogentry.__class__.cw_skip_copy_for = []

Adrien Di Mascio's avatar
Adrien Di Mascio committed
530
    def test_nonregr_eetype_etype_editing(self):
531
        """non-regression test checking that a manager user can edit a CWEType entity
Adrien Di Mascio's avatar
Adrien Di Mascio committed
532
        """
533
        groupeids = sorted(eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")'))
Sylvain Thénault's avatar
Sylvain Thénault committed
534
535
536
537
        groups = [u(eid) for eid in groupeids]
        cwetypeeid = self.execute('CWEType X WHERE X name "CWEType"')[0][0]
        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X read_permission G, X eid %(x)s', {'x': cwetypeeid})]
        cwetypeeid = u(cwetypeeid)
538
539
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
540
541
            'eid':      cwetypeeid,
            '__type:'+cwetypeeid:  'CWEType',
542
            '_cw_entity_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
543
            'name-subject:'+cwetypeeid:     u'CWEType',
Sylvain Thénault's avatar
Sylvain Thénault committed
544
            'final-subject:'+cwetypeeid:    '',
Sylvain Thénault's avatar
Sylvain Thénault committed
545
546
            'description-subject:'+cwetypeeid:     u'users group',
            'read_permission-subject:'+cwetypeeid:  groups,
547
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
548
        try:
549
            path, params = self.expect_redirect_handle_request(req, 'edit')
550
            e = self.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}).get_entity(0, 0)
551
552
            self.assertEqual(e.name, 'CWEType')
            self.assertEqual(sorted(g.eid for g in e.read_permission), groupeids)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
553
554
        finally:
            # restore
555
            self.execute('SET X read_permission Y WHERE X name "CWEType", Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups)))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
556
            self.commit()
557

Adrien Di Mascio's avatar
Adrien Di Mascio committed
558
559
560
561
    def test_nonregr_strange_text_input(self):
        """non-regression test checking text input containing "13:03:43"

        this seems to be postgres (tsearch?) specific
562
        """
563
564
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
565
            'eid': 'A', '__maineid' : 'A',
566
            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'title-subject,content-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
567
568
            'title-subject:A': u'"13:03:40"',
            'content-subject:A': u'"13:03:43"',}
569
        path, params = self.expect_redirect_handle_request(req, 'edit')
570
        self.assertTrue(path.startswith('blogentry/'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
571
        eid = path.split('/')[1]
572
        e = self.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}).get_entity(0, 0)
573
574
        self.assertEqual(e.title, '"13:03:40"')
        self.assertEqual(e.content, '"13:03:43"')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
575
576
577


    def test_nonregr_multiple_empty_email_addr(self):
578
        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
579
580
        req = self.request()
        req.form = {'eid': ['X', 'Y'],
581

582
                    '__type:X': 'CWUser',
583
                    '_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
584
585
586
                    'login-subject:X': u'adim',
                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
                    'in_group-subject:X': `gueid`,
587

588
                    '__type:Y': 'EmailAddress',
589
                    '_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object',
Sylvain Thénault's avatar
Sylvain Thénault committed
590
591
592
                    'address-subject:Y': u'',
                    'alias-subject:Y': u'',
                    'use_email-object:Y': 'X',
593
                    }
594
595
596
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
        self.assertEqual(cm.exception.errors, {'address-subject': u'required field'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
597
598
599

    def test_nonregr_copy(self):
        user = self.user()
600
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
601
602
        req.form = {'__maineid' : 'X', 'eid': 'X',
                    '__cloned_eid:X': user.eid, '__type:X': 'CWUser',
603
                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
604
605
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
606
                    }
607
        path, params = self.expect_redirect_handle_request(req, 'edit')
608
        self.assertEqual(path, 'cwuser/toto')
609
        e = self.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0)
610
611
        self.assertEqual(e.login, 'toto')
        self.assertEqual(e.in_group[0].name, 'managers')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
612
613
614


    def test_nonregr_rollback_on_validation_error(self):
615
616
        req = self.request()
        p = self.create_user(req, "doe")
Adrien Di Mascio's avatar
Adrien Di Mascio committed
617
618
619
620
        # do not try to skip 'primary_email' for this test
        old_skips = p.__class__.skip_copy_for
        p.__class__.skip_copy_for = ()
        try:
Sylvain Thénault's avatar
Sylvain Thénault committed
621
            e = self.request().create_entity('EmailAddress', address=u'doe@doe.com')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
622
623
            self.execute('SET P use_email E, P primary_email E WHERE P eid %(p)s, E eid %(e)s',
                         {'p' : p.eid, 'e' : e.eid})
624
            req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
625
626
            req.form = {'eid': 'X',
                        '__cloned_eid:X': p.eid, '__type:X': 'CWUser',
627
                        '_cw_entity_fields:X': 'login-subject,surname-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
628
629
                        'login-subject': u'dodo',
                        'surname-subject:X': u'Boom',
630
                        '__errorurl' : "whatever but required",
Sylvain Thénault's avatar
Sylvain Thénault committed
631
                        }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
632
633
634
635
636
            # try to emulate what really happens in the web application
            # 1/ validate form => EditController.publish raises a ValidationError
            #    which fires a Redirect
            # 2/ When re-publishing the copy form, the publisher implicitly commits
            try:
637
                self.app_handle_request(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
638
            except Redirect:
Sylvain Thénault's avatar
Sylvain Thénault committed
639
                req = self.request()
640
641
                req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
                req.form['vid'] = 'copy'
642
                self.app_handle_request(req, 'view')
643
            rset = self.execute('CWUser P WHERE P surname "Boom"')
644
            self.assertEqual(len(rset), 0)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
645
646
647
648
        finally:
            p.__class__.skip_copy_for = old_skips


649
class ReportBugControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
650

651
    def test_usable_by_guest(self):
652
        self.login('anon')
Sylvain Thénault's avatar
Sylvain Thénault committed
653
654
655
        self.assertRaises(NoSelectableObject,
                          self.vreg['controllers'].select, 'reportbug', self.request())
        self.vreg['controllers'].select('reportbug', self.request(description='hop'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
656
657


658
659
class AjaxControllerTC(CubicWebTC):
    tested_controller = 'ajax'
Adrien Di Mascio's avatar
Adrien Di Mascio committed
660
661
662

    def ctrl(self, req=None):
        req = req or self.request(url='http://whatever.fr/')
663
        return self.vreg['controllers'].select(self.tested_controller, req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
664
665

    def setup_database(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
666
667
668
        req = self.request()
        self.pytag = req.create_entity('Tag', name=u'python')
        self.cubicwebtag = req.create_entity('Tag', name=u'cubicweb')
669
        self.john = self.create_user(req, u'John')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
670
671
672
673


    ## tests ##################################################################
    def test_simple_exec(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
674
675
676
677
        req = self.request(rql='CWUser P WHERE P login "John"',
                           pageid='123', fname='view')
        ctrl = self.ctrl(req)
        rset = self.john.as_rset()
678
        rset.req = req
679
        source = ctrl.publish()
680
        self.assertTrue(source.startswith('<div>'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
681

sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
682
683
684
#     def test_json_exec(self):
#         rql = 'Any T,N WHERE T is Tag, T name N'
#         ctrl = self.ctrl(self.request(mode='json', rql=rql, pageid='123'))
685
#         self.assertEqual(ctrl.publish(),
686
#                           json_dumps(self.execute(rql).rows))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
687
688
689

    def test_remote_add_existing_tag(self):
        self.remote_call('tag_entity', self.john.eid, ['python'])
690
        self.assertItemsEqual(
691
692
            [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
            ['python', 'cubicweb'])
693
        self.assertEqual(
694
695
            self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
            [['python']])
696

Adrien Di Mascio's avatar
Adrien Di Mascio committed
697
698
    def test_remote_add_new_tag(self):
        self.remote_call('tag_entity', self.john.eid, ['javascript'])
699
        self.assertItemsEqual(
700
701
            [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
            ['python', 'cubicweb', 'javascript'])
702
        self.assertEqual(
703
704
            self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
            [['javascript']])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
705
706

    def test_pending_insertion(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
707
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '13']])
Sylvain Thénault's avatar
Sylvain Thénault committed
708
        deletes = get_pending_deletes(req)
709
        self.assertEqual(deletes, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
710
        inserts = get_pending_inserts(req)
711
        self.assertEqual(inserts, ['12:tags:13'])
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
712
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Sylvain Thénault's avatar
Sylvain Thénault committed
713
        deletes = get_pending_deletes(req)
714
        self.assertEqual(deletes, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
715
        inserts = get_pending_inserts(req)
716
        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
717
        inserts = get_pending_inserts(req, 12)
718
        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
719
        inserts = get_pending_inserts(req, 13)
720
        self.assertEqual(inserts, ['12:tags:13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
721
        inserts = get_pending_inserts(req, 14)
722
        self.assertEqual(inserts, ['12:tags:14'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
723
724
725
726
        req.remove_pending_operations()

    def test_pending_deletion(self):
        res, req = self.remote_call('add_pending_delete', ['12', 'tags', '13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
727
        inserts = get_pending_inserts(req)
728
        self.assertEqual(inserts, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
729
        deletes = get_pending_deletes(req)
730
        self.assertEqual(deletes, ['12:tags:13'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
731
        res, req = self.remote_call('add_pending_delete', ['12', 'tags', '14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
732
        inserts = get_pending_inserts(req)
733
        self.assertEqual(inserts, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
734
        deletes = get_pending_deletes(req)
735
        self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
736
        deletes = get_pending_deletes(req, 12)
737
        self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
738
        deletes = get_pending_deletes(req, 13)
739
        self.assertEqual(deletes, ['12:tags:13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
740
        deletes = get_pending_deletes(req, 14)
741
        self.assertEqual(deletes, ['12:tags:14'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
742
743
744
745
        req.remove_pending_operations()

    def test_remove_pending_operations(self):
        self.remote_call('add_pending_delete', ['12', 'tags', '13'])
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
746
        _, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Sylvain Thénault's avatar
Sylvain Thénault committed
747
        inserts = get_pending_inserts(req)
748
        self.assertEqual(inserts, ['12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
749
        deletes = get_pending_deletes(req)
750
        self.assertEqual(deletes, ['12:tags:13'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
751
        req.remove_pending_operations()
752
753
        self.assertEqual(get_pending_deletes(req), [])
        self.assertEqual(get_pending_inserts(req), [])
754

Adrien Di Mascio's avatar
Adrien Di Mascio committed
755
756
757
758

    def test_add_inserts(self):
        res, req = self.remote_call('add_pending_inserts',
                                    [('12', 'tags', '13'), ('12', 'tags', '14')])
Sylvain Thénault's avatar
Sylvain Thénault committed
759
        inserts = get_pending_inserts(req)
760
        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
761
        req.remove_pending_operations()
762

Adrien Di Mascio's avatar
Adrien Di Mascio committed
763
764
765

    # silly tests
    def test_external_resource(self):
766
        self.assertEqual(self.remote_call('external_resource', 'RSS_LOGO')[0],
767
                          json_dumps(self.config.uiprops['RSS_LOGO']))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
768
    def test_i18n(self):
769
        self.assertEqual(self.remote_call('i18n', ['bimboom'])[0],
770
                          json_dumps(['bimboom']))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
771
772

    def test_format_date(self):
773
        self.assertEqual(self.remote_call('format_date', '2007-01-01 12:00:00')[0],
774
                          json_dumps('2007/01/01'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
775

776
777
778
779
    def test_ajaxfunc_noparameter(self):
        @ajaxfunc
        def foo(self, x, y):
            return 'hello'
780
781
782
783
784
785
        self.assertEqual(foo(object, 1, 2), 'hello')
        appobject = foo.__appobject__
        self.assertTrue(issubclass(appobject, AjaxFunction))
        self.assertEqual(appobject.__regid__, 'foo')
        self.assertEqual(appobject.check_pageid, False)
        self.assertEqual(appobject.output_type, None)
786
        req = self.request()
787
        f = appobject(req)
788
789
790
        self.assertEqual(f(12, 13), 'hello')

    def test_ajaxfunc_checkpageid(self):
791
        @ajaxfunc(check_pageid=True)
792
        def foo(self, x, y):
793
794
795
796
797
798
799
            return 'hello'
        self.assertEqual(foo(object, 1, 2), 'hello')
        appobject = foo.__appobject__
        self.assertTrue(issubclass(appobject, AjaxFunction))
        self.assertEqual(appobject.__regid__, 'foo')
        self.assertEqual(appobject.check_pageid, True)
        self.assertEqual(appobject.output_type, None)
800
801
        # no pageid
        req = self.request()
802
        f = appobject(req)