source: main/waeup.kofa/trunk/src/waeup/kofa/utils/tests/test_converters.py @ 8192

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

Make import converters more modular (support special converters for special zope.schema field types) and support lists and result entries as import input.

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