source: main/waeup.sirp/trunk/src/waeup/sirp/utils/tests/test_converters.py @ 6278

Last change on this file since 6278 was 6278, checked in by uli, 13 years ago

Add extended bools widget. This one accepts also '1', 'true', 'yes' as True values, which is handy when importing CSV
files. We have to register this new widget overriding the default. Maybe a bit overkill?

File size: 12.1 KB
Line 
1##
2## test_converters.py
3## Login : <uli@pu.smp.net>
4## Started on  Tue May 31 08:34:44 2011 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2011 Uli Fouquet
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
22"""
23Tests for converterts.
24"""
25import datetime
26import os
27import shutil
28import tempfile
29import unittest
30from zope import schema
31from zope.app.testing.functional import FunctionalTestCase
32from zope.component import provideUtility
33from zope.component.factory import Factory
34from zope.component.hooks import setSite, clearSite
35from zope.component.interfaces import IFactory
36from zope.formlib import form
37from zope.interface import (
38    Interface, implements, invariant, Invalid, implementedBy)
39from zope.interface.verify import verifyClass, verifyObject
40
41from waeup.sirp.app import University
42from waeup.sirp.testing import FunctionalLayer, doctestsuite_for_module
43from waeup.sirp.utils.converters import IObjectConverter
44from waeup.sirp.utils.helpers import attrs_to_fields
45from waeup.sirp.interfaces import SimpleWAeUPVocabulary
46
47colors = SimpleWAeUPVocabulary(
48    ('Red', u'red'),
49    ('Green', u'green'),
50    ('Blue', u'blue'),
51    )
52car_nums = SimpleWAeUPVocabulary(
53    ('None', 0),
54    ('One', 1),
55    ('Two', 2),
56    ('Three', 3),
57    )
58class IContact(Interface):
59    """Sample interface for sample content type used here in tests.
60    """
61    name = schema.TextLine(
62        title = u'Name',
63        default = u'Manfred',
64        readonly = True,
65        )
66    age = schema.Int(
67        title = u'Age',
68        default = 23,
69        required = True,
70        )
71    city = schema.TextLine(
72        title = u'City',
73        required = True,
74        )
75    vip = schema.Bool(
76        title = u'Celebrity',
77        default = False,
78        required = True,
79        )
80    birthday = schema.Date(
81        title = u'Birthday',
82        default = None,
83        )
84    fav_color = schema.Choice(
85        title = u'Favourite color',
86        default = u'red',
87        vocabulary = colors,
88        )
89    num_cars = schema.Choice(
90        title = u'Number of cars owned',
91        default = None,
92        vocabulary = car_nums,
93        )
94    @invariant
95    def kevinIsYoung(contact):
96        if contact.age > 16 and contact.name == 'Kevin':
97            raise Invalid('Kevins are age 16 or below.')
98
99class Contact(object):
100    """Sample content type.
101    """
102    implements(IContact)
103Contact = attrs_to_fields(Contact)
104
105form_fields_select = form.Fields(IContact).select('name', 'vip')
106form_fields_omit = form.Fields(IContact).omit('name', 'vip')
107
108class ContactFactory(object):
109    """A factory for faculty containers.
110    """
111    implements(IContact)
112
113    def __call__(self, *args, **kw):
114        return Faculty()
115
116    def getInterfaces(self):
117        return implementedBy(Faculty)
118
119class ConverterTests(FunctionalTestCase):
120
121    layer = FunctionalLayer
122
123    def setUp(self):
124        super(ConverterTests, self).setUp()
125
126        # Setup a sample site for each test
127        app = University()
128        self.dc_root = tempfile.mkdtemp()
129        app['datacenter'].setStoragePath(self.dc_root)
130
131        # Prepopulate the ZODB...
132        self.getRootFolder()['app'] = app
133        self.app = self.getRootFolder()['app']
134
135        self.workdir = tempfile.mkdtemp()
136
137        # Create a factory for contacts and register it as global utility
138        factory = Factory(Contact)
139        provideUtility(factory, IFactory, 'contact')
140        return
141
142    def tearDown(self):
143        super(ConverterTests, self).tearDown()
144        shutil.rmtree(self.workdir)
145        shutil.rmtree(self.dc_root)
146        clearSite()
147        return
148
149    def test_valid_data(self):
150        contact = Contact()
151        contact.age = 33
152        input_data = dict(name='Rudi', age='99')
153        converter = IObjectConverter(IContact) # a converter to IContact
154        err, inv_err, data = converter.fromStringDict(
155            input_data, contact)
156        assert data['name'] == 'Rudi'
157        assert data['age'] == 99
158        return
159
160    def test_bool(self):
161        contact1 = Contact()
162        contact2 = Contact()
163        input_data1 = dict(vip='on')
164        input_data2 = dict(vip='')
165        converter = IObjectConverter(IContact) # a converter to IContact
166        err1, inv_err1, data1 = converter.fromStringDict(
167            input_data1, contact1)
168        err2, inv_err2, data2 = converter.fromStringDict(
169            input_data2, contact2)
170        assert data1['vip'] is True
171        assert data2['vip'] is False
172
173    def test_bool_nonstandard_values1(self):
174        # We accept 'true', 'True', 'tRuE', 'faLSE' and similar.
175        contact1 = Contact()
176        contact2 = Contact()
177        input_data1 = dict(vip='True')
178        input_data2 = dict(vip='false')
179        converter = IObjectConverter(IContact) # a converter to IContact
180        err1, inv_err1, data1 = converter.fromStringDict(
181            input_data1, contact1)
182        err2, inv_err2, data2 = converter.fromStringDict(
183            input_data2, contact2)
184        assert data1['vip'] is True
185        assert data2['vip'] is False
186
187    def test_bool_nonstandard_values2(self):
188        # We accept '1' and '0' as bool values.
189        contact1 = Contact()
190        contact2 = Contact()
191        input_data1 = dict(vip='1')
192        input_data2 = dict(vip='0')
193        converter = IObjectConverter(IContact) # a converter to IContact
194        err1, inv_err1, data1 = converter.fromStringDict(
195            input_data1, contact1)
196        err2, inv_err2, data2 = converter.fromStringDict(
197            input_data2, contact2)
198        assert data1['vip'] is True
199        assert data2['vip'] is False
200
201    def test_bool_nonstandard_values3(self):
202        # We accept 'yEs', 'no' and similar as bool values.
203        contact1 = Contact()
204        contact2 = Contact()
205        input_data1 = dict(vip='Yes')
206        input_data2 = dict(vip='no')
207        converter = IObjectConverter(IContact) # a converter to IContact
208        err1, inv_err1, data1 = converter.fromStringDict(
209            input_data1, contact1)
210        err2, inv_err2, data2 = converter.fromStringDict(
211            input_data2, contact2)
212        assert data1['vip'] is True
213        assert data2['vip'] is False
214
215    def test_int(self):
216        contact = Contact()
217        input_data = dict(age='99')
218        converter = IObjectConverter(IContact) # a converter to IContact
219        err, inv_err, data = converter.fromStringDict(
220            input_data, contact)
221        assert data['age'] == 99
222        return
223
224    def test_int_invalid(self):
225        contact = Contact()
226        input_data = dict(age='sweet sixteen')
227        converter = IObjectConverter(IContact) # a converter to IContact
228        err, inv_err, new_contact = converter.fromStringDict(
229            input_data, contact)
230        self.assertEqual(err, [('age', u'Invalid integer data')])
231        return
232
233    def test_textline(self):
234        contact = Contact()
235        input_data = dict(name='Rudi')
236        converter = IObjectConverter(IContact) # a converter to IContact
237        err, inv_err, data = converter.fromStringDict(
238            input_data, contact)
239        self.assertEqual(data['name'], u'Rudi')
240        assert isinstance(data['name'], unicode)
241        return
242
243    def test_invariant(self):
244        contact = Contact()
245        input_data = dict(name='Kevin', age='22')
246        converter = IObjectConverter(IContact) # a converter to IContact
247        err, inv_err, new_contact = converter.fromStringDict(
248            input_data, contact)
249        self.assertEqual(inv_err, ['Kevins are age 16 or below.'])
250        return
251
252    def test_date(self):
253        contact = Contact()
254        converter = IObjectConverter(IContact) # a converter to IContact
255        err, inv_err, data = converter.fromStringDict(
256            dict(birthday='1945/12/23'), contact)
257        assert data['birthday'] == datetime.date(1945, 12, 23)
258        assert isinstance(data['birthday'], datetime.date)
259
260        err, inv_err, data = converter.fromStringDict(
261            dict(birthday='1945/23/12'), contact)
262        assert data['birthday'] == datetime.date(1945, 12, 23)
263
264        #err, inv_err, data = converter.fromStringDict(
265        #    dict(birthday='23/12/1945'), contact)
266        #assert data['birthday'] == datetime.date(1945, 12, 23)
267
268        #err, inv_err, data = converter.fromStringDict(
269        #    dict(birthday='23.12.1945'), contact)
270        #assert data['birthday'] == datetime.date(1945, 12, 23)
271
272        #err, inv_err, data = converter.fromStringDict(
273        #    dict(birthday='23-12-1945'), contact)
274        #assert data['birthday'] == datetime.date(1945, 12, 23)
275        return
276
277    def test_date_invalid(self):
278        contact = Contact()
279        converter = IObjectConverter(IContact) # a converter to IContact
280        err, inv_err, data = converter.fromStringDict(
281            dict(birthday='not-a-date'), contact)
282        self.assertEqual(err, [('birthday', u'Invalid datetime data')])
283
284    def test_inject_formfields_select(self):
285        # We can use our own formfields and select only a subset of fields
286        contact = Contact()
287        converter = IObjectConverter(IContact) # a converter to IContact
288        input_data = dict(name='Bruno', age='99', vip='on')
289        err, inv_err, data = converter.fromStringDict(
290            input_data, contact, form_fields=form_fields_select)
291        self.assertEqual(data['name'], 'Bruno')
292        assert 'age' not in data.keys()
293        assert data['vip'] is True
294        return
295
296    def test_inject_formfields_omit(self):
297        # We can use our own formfields and omit some fields
298        contact = Contact()
299        converter = IObjectConverter(IContact) # a converter to IContact
300        input_data = dict(name='Bruno', age='99', vip='on')
301        err, inv_err, data = converter.fromStringDict(
302            input_data, contact, form_fields=form_fields_omit)
303        self.assertEqual(data['age'], 99)
304        assert 'name' not in data.keys()
305        assert 'vip' not in data.keys()
306        return
307
308    def test_factory(self):
309        # We can use factories to convert values
310        converter = IObjectConverter(IContact) # a converter to IContact
311        # pass string ``contact`` instead of a real object
312        err, inv_err, data = converter.fromStringDict(
313            dict(name='Gabi', age='23'), 'contact')
314        self.assertEqual(data['age'], 23)
315        self.assertEqual(data['name'], u'Gabi')
316        return
317
318    def test_choice_vocab(self):
319        # We can handle vocabularies
320        converter = IObjectConverter(IContact) # a converter to IContact
321        err, inv_err, data = converter.fromStringDict(
322            dict(fav_color='blue'), 'contact')
323        assert data['fav_color'] == u'blue'
324        assert isinstance(data['fav_color'], unicode)
325        return
326
327    def test_choice_vocab_invalid_value(self):
328        # We can handle vocabularies
329        converter = IObjectConverter(IContact) # a converter to IContact
330        err, inv_err, data = converter.fromStringDict(
331            dict(fav_color='magenta'), 'contact')
332        self.assertEqual(err, [('fav_color', u'Invalid value')])
333        assert 'fav_color' not in data.keys()
334        return
335
336    def test_non_string_choice(self):
337        # We can handle vocabs with non-string values
338        converter = IObjectConverter(IContact) # a converter to IContact
339        err, inv_err, data = converter.fromStringDict(
340            dict(num_cars='1'), 'contact')
341        assert data['num_cars'] == 1
342        return
343
344
345def test_suite():
346    suite = unittest.TestSuite()
347    for testcase in [
348        ConverterTests,
349        ]:
350        suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
351                testcase
352                )
353        )
354    return suite
355
Note: See TracBrowser for help on using the repository browser.