1# Copyright 2017 CodiLime
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from __future__ import unicode_literals
16
17import unittest
18import six
19
20from veles.data.bindata import BinData
21from veles.schema.nodeid import NodeID
22from veles.schema import fields, enumeration
23from veles.proto.exceptions import VelesException, SchemaError
24
25
26class Piwo(object):
27    def dump(self):
28        return 'piwo'
29
30    @classmethod
31    def load(cls, value):
32        if value != 'piwo':
33            raise SchemaError
34        return Piwo()
35
36    def __eq__(self, other):
37        return type(self) == type(other)
38
39    def __ne__(self, other):
40        return not self.__eq__(other)
41
42    def __hash__(self):
43        return 13
44
45
46class Zlew(object):
47    def dump(self):
48        return 'zlew'
49
50    @classmethod
51    def load(cls, value):
52        if value != 'zlew':
53            raise SchemaError
54        return Zlew()
55
56    def __eq__(self, other):
57        return type(self) == type(other)
58
59    def __ne__(self, other):
60        return not self.__eq__(other)
61
62    def __hash__(self):
63        return 13
64
65
66class ZlewType(enumeration.EnumModel):
67    ZLEW = 'zlewzlewzlew'
68    TURBOZLEW = b'turbo'
69    DWUZLEW = 2
70
71
72class TestFields(unittest.TestCase):
73    def test_field(self):
74        a = fields.Any(default='zlew')
75        a.__set_name__(None, 'a')
76        self.assertEqual(a.name, 'a')
77        a.validate(1234)
78        a.validate({})
79        with self.assertRaises(SchemaError):
80            a.validate(None)
81        tv = {
82            'a': 123,
83            'b': 'c',
84        }
85        self.assertEqual(a.dump(tv), tv)
86        self.assertEqual(a.load(tv), tv)
87        with self.assertRaises(SchemaError):
88            a.load(None)
89
90        with self.assertRaises(TypeError):
91            fields.Any(optional='zlew')
92        with self.assertRaises(ValueError):
93            a = fields.Any(optional=True, default='zlew')
94
95    def test_empty(self):
96        with self.assertRaises(TypeError):
97            fields.Empty(default='zlew')
98        with self.assertRaises(TypeError):
99            fields.Empty(optional=False)
100
101        a = fields.Empty()
102        a.validate(None)
103        self.assertEqual(a.dump(None), None)
104        self.assertEqual(a.load(None), None)
105        with self.assertRaises(SchemaError):
106            a.validate(1)
107        with self.assertRaises(SchemaError):
108            a.load(1)
109
110    def test_boolean(self):
111        with self.assertRaises(SchemaError):
112            fields.Boolean(default='zlew')
113
114        a = fields.Boolean(optional=True)
115        a.validate(True)
116        a.validate(False)
117        a.validate(None)
118        with self.assertRaises(SchemaError):
119            a.validate(1)
120        self.assertEqual(a.dump(None), None)
121        self.assertEqual(a.dump(True), True)
122        self.assertEqual(a.dump(False), False)
123        self.assertEqual(a.load(None), None)
124        self.assertEqual(a.load(True), True)
125        self.assertEqual(a.load(False), False)
126        with self.assertRaises(SchemaError):
127            a.load(1)
128
129    def test_float(self):
130        a = fields.Float()
131        a.validate(1.234)
132        with self.assertRaises(SchemaError):
133            a.validate(1)
134        with self.assertRaises(SchemaError):
135            a.validate('1.0')
136        self.assertEqual(a.dump(1.234), 1.234)
137        self.assertEqual(a.load(1.234), 1.234)
138        with self.assertRaises(SchemaError):
139            a.load(1)
140        with self.assertRaises(SchemaError):
141            a.load('1.0')
142
143    def test_string(self):
144        a = fields.String()
145        a.validate('abcd')
146        with self.assertRaises(SchemaError):
147            a.validate(b'abcd')
148        with self.assertRaises(SchemaError):
149            a.validate(1234)
150        self.assertEqual(a.dump('abcd'), 'abcd')
151        self.assertEqual(a.load('abcd'), 'abcd')
152        with self.assertRaises(SchemaError):
153            a.load(b'abcd')
154        with self.assertRaises(SchemaError):
155            a.load(1234)
156
157    def test_binary(self):
158        a = fields.Binary()
159        a.validate(b'abcd')
160        with self.assertRaises(SchemaError):
161            a.validate('abcd')
162        with self.assertRaises(SchemaError):
163            a.validate(1234)
164        self.assertEqual(a.dump(b'abcd'), b'abcd')
165        self.assertEqual(a.load(b'abcd'), b'abcd')
166        with self.assertRaises(SchemaError):
167            a.load('abcd')
168        with self.assertRaises(SchemaError):
169            a.load(1234)
170
171    def test_nodeid(self):
172        a = fields.NodeID()
173        id = NodeID()
174        a.validate(id)
175        with self.assertRaises(SchemaError):
176            a.validate(b'abcd')
177        with self.assertRaises(SchemaError):
178            a.validate(1234)
179        self.assertEqual(a.dump(id), id)
180        self.assertEqual(a.load(id), id)
181        with self.assertRaises(SchemaError):
182            a.load(b'abcd')
183        with self.assertRaises(SchemaError):
184            a.load(1234)
185
186    def test_bindata(self):
187        a = fields.BinData()
188        data = BinData(8, [0x12, 0x34])
189        a.validate(data)
190        with self.assertRaises(SchemaError):
191            a.validate(b'abcd')
192        with self.assertRaises(SchemaError):
193            a.validate(1234)
194        self.assertEqual(a.dump(data), data)
195        self.assertEqual(a.load(data), data)
196        with self.assertRaises(SchemaError):
197            a.load(b'abcd')
198        with self.assertRaises(SchemaError):
199            a.load(1234)
200
201    def test_integer(self):
202        a = fields.Integer()
203        a.validate(0)
204        a.validate(1)
205        a.validate(-1)
206        a.validate(0x123456789abcdef123456789abcdef)
207        a.validate(-0x123456789abcdef123456789abcdef)
208        with self.assertRaises(SchemaError):
209            a.validate(False)
210        with self.assertRaises(SchemaError):
211            a.validate(True)
212
213        a = fields.Integer(minimum=-123, maximum=456)
214        a.validate(-123)
215        a.validate(123)
216        a.validate(234)
217        a.validate(456)
218        with self.assertRaises(SchemaError):
219            a.validate(-0x123456789abcdef123456789abcdef)
220        with self.assertRaises(SchemaError):
221            a.validate(-124)
222        with self.assertRaises(SchemaError):
223            a.validate(457)
224        with self.assertRaises(SchemaError):
225            a.validate(0x123456789abcdef123456789abcdef)
226
227        a = fields.Integer(minimum=123)
228        a.validate(123)
229        a.validate(234)
230        a.validate(456)
231        a.validate(0x123456789abcdef123456789abcdef)
232        with self.assertRaises(SchemaError):
233            a.validate(0)
234        with self.assertRaises(SchemaError):
235            a.validate(-123)
236        with self.assertRaises(SchemaError):
237            a.validate(122)
238
239        with self.assertRaises(TypeError):
240            fields.Integer(minimum='zlew')
241        with self.assertRaises(TypeError):
242            fields.Integer(maximum='zlew')
243        fields.Integer(minimum=3, maximum=3)
244        fields.Integer(minimum=3)
245        fields.Integer(maximum=3)
246        with self.assertRaises(ValueError):
247            fields.Integer(minimum=3, maximum=2)
248
249    def test_unsigned_integer(self):
250        a = fields.UnsignedInteger()
251        a.validate(0)
252        a.validate(1)
253        a.validate(123)
254        a.validate(0x123456789abcdef123456789abcdef)
255        with self.assertRaises(SchemaError):
256            a.validate(-122)
257        with self.assertRaises(SchemaError):
258            a.validate(-1)
259        with self.assertRaises(SchemaError):
260            a.validate(-0x123456789abcdef123456789abcdef)
261
262        with self.assertRaises(ValueError):
263            fields.UnsignedInteger(minimum=-1)
264        with self.assertRaises(TypeError):
265            fields.UnsignedInteger(minimum=None)
266        with self.assertRaises(ValueError):
267            fields.UnsignedInteger(maximum=-1)
268        fields.UnsignedInteger(maximum=0)
269        fields.UnsignedInteger(minimum=123)
270        fields.UnsignedInteger(maximum=123)
271        fields.UnsignedInteger(maximum=None)
272
273    def test_small_integer(self):
274        a = fields.SmallInteger()
275        a.validate(0)
276        a.validate(-1)
277        a.validate(1)
278        a.validate(-0x8000000000000000)
279        a.validate(0x7fffffffffffffff)
280        with self.assertRaises(SchemaError):
281            a.validate(-0x8000000000000001)
282        with self.assertRaises(SchemaError):
283            a.validate(0x8000000000000000)
284        fields.SmallInteger(minimum=-1)
285        fields.SmallInteger(maximum=-1)
286        fields.SmallInteger(maximum=0x7fffffffffffffff)
287        fields.SmallInteger(minimum=-0x8000000000000000)
288        with self.assertRaises(ValueError):
289            fields.SmallInteger(maximum=0x8000000000000000)
290        with self.assertRaises(ValueError):
291            fields.SmallInteger(minimum=-0x8000000000000001)
292        with self.assertRaises(TypeError):
293            fields.SmallInteger(maximum=None)
294        with self.assertRaises(TypeError):
295            fields.SmallInteger(minimum=None)
296
297    def test_small_unsigned_integer(self):
298        a = fields.SmallUnsignedInteger()
299        a.validate(0)
300        a.validate(1)
301        a.validate(0xffffffffffffffff)
302        with self.assertRaises(SchemaError):
303            a.validate(-1)
304        with self.assertRaises(SchemaError):
305            a.validate(0x10000000000000000)
306        fields.SmallUnsignedInteger(minimum=1)
307        fields.SmallUnsignedInteger(maximum=1)
308        fields.SmallUnsignedInteger(maximum=0xffffffffffffffff)
309        fields.SmallUnsignedInteger(minimum=0)
310        with self.assertRaises(ValueError):
311            fields.SmallUnsignedInteger(maximum=0x10000000000000000)
312        with self.assertRaises(ValueError):
313            fields.SmallUnsignedInteger(minimum=-1)
314        with self.assertRaises(TypeError):
315            fields.SmallUnsignedInteger(maximum=None)
316        with self.assertRaises(TypeError):
317            fields.SmallUnsignedInteger(minimum=None)
318
319    def test_object(self):
320        a = fields.Object(Piwo, optional=True)
321        a.validate(None)
322        a.validate(Piwo())
323        with self.assertRaises(SchemaError):
324            a.validate('piwo')
325        with self.assertRaises(SchemaError):
326            a.validate(Zlew())
327        self.assertIsInstance(a.load('piwo'), Piwo)
328        with self.assertRaises(SchemaError):
329            a.load('zlew')
330        self.assertEqual(a.load(None), None)
331        self.assertEqual(a.dump(Piwo()), 'piwo')
332        self.assertEqual(a.dump(None), None)
333
334        a = fields.Object(Zlew)
335        a.validate(Zlew())
336        with self.assertRaises(SchemaError):
337            a.validate('zlew')
338        with self.assertRaises(SchemaError):
339            a.validate(Piwo())
340        with self.assertRaises(SchemaError):
341            a.validate(None)
342        self.assertIsInstance(a.load('zlew'), Zlew)
343        with self.assertRaises(SchemaError):
344            a.load('piwo')
345        with self.assertRaises(SchemaError):
346            a.load(None)
347        self.assertEqual(a.dump(Zlew()), 'zlew')
348
349        fields.Object(Zlew, default=Zlew())
350        with self.assertRaises(SchemaError):
351            fields.Object(Zlew, default=Piwo())
352
353    def test_list(self):
354        a = fields.List(fields.Object(Piwo))
355        a.validate([])
356        a.validate([Piwo()])
357        a.validate([Piwo(), Piwo(), Piwo()])
358        with self.assertRaises(SchemaError):
359            a.validate(Piwo())
360        with self.assertRaises(SchemaError):
361            a.validate(set())
362        with self.assertRaises(SchemaError):
363            a.validate(None)
364        with self.assertRaises(SchemaError):
365            a.validate([Piwo(), Zlew(), Piwo()])
366        with self.assertRaises(SchemaError):
367            a.validate([Piwo(), None])
368        self.assertEqual(a.load([]), [])
369        self.assertEqual(a.load(['piwo', 'piwo']), [Piwo(), Piwo()])
370        with self.assertRaises(SchemaError):
371            a.validate(a.load({}))
372        with self.assertRaises(SchemaError):
373            a.validate(a.load(None))
374        with self.assertRaises(SchemaError):
375            a.validate(a.load('piwo'))
376        with self.assertRaises(SchemaError):
377            a.validate(a.load(['zlew']))
378        with self.assertRaises(SchemaError):
379            a.validate(a.load(['piwo', None]))
380        self.assertEqual(a.dump([]), [])
381        self.assertEqual(a.dump([Piwo(), Piwo()]), ['piwo', 'piwo'])
382        fields.List(fields.Integer(), default=[1, 2, 3])
383
384    def test_set(self):
385        a = fields.Set(fields.Object(Piwo))
386        a.validate(set())
387        a.validate({Piwo()})
388        with self.assertRaises(SchemaError):
389            a.validate(Piwo())
390        with self.assertRaises(SchemaError):
391            a.validate([])
392        with self.assertRaises(SchemaError):
393            a.validate(None)
394        with self.assertRaises(SchemaError):
395            a.validate({Piwo(), Zlew()})
396        with self.assertRaises(SchemaError):
397            a.validate({Piwo(), None})
398        self.assertEqual(a.load([]), set())
399        self.assertEqual(a.load(['piwo']), {Piwo()})
400        with self.assertRaises(SchemaError):
401            a.validate(a.load({}))
402        with self.assertRaises(SchemaError):
403            a.validate(a.load(None))
404        with self.assertRaises(SchemaError):
405            a.validate(a.load('piwo'))
406        with self.assertRaises(SchemaError):
407            a.validate(a.load(['zlew']))
408        with self.assertRaises(SchemaError):
409            a.validate(a.load(['piwo', None]))
410        self.assertEqual(a.dump({}), [])
411        self.assertEqual(a.dump({Piwo()}), ['piwo'])
412        fields.Set(fields.Integer(), default={1, 2, 3})
413
414    def test_map(self):
415        a = fields.Map(fields.Object(Piwo), fields.Object(Zlew))
416        a.validate({})
417        a.validate({Piwo(): Zlew()})
418        with self.assertRaises(SchemaError):
419            a.validate(Piwo())
420        with self.assertRaises(SchemaError):
421            a.validate(Zlew())
422        with self.assertRaises(SchemaError):
423            a.validate([])
424        with self.assertRaises(SchemaError):
425            a.validate(None)
426        with self.assertRaises(SchemaError):
427            a.validate({Piwo(): Piwo()})
428        with self.assertRaises(SchemaError):
429            a.validate({Zlew(): Zlew()})
430        with self.assertRaises(SchemaError):
431            a.validate({Zlew(): Piwo()})
432        with self.assertRaises(SchemaError):
433            a.validate({Piwo(): None})
434        with self.assertRaises(SchemaError):
435            a.validate({None: Zlew()})
436        self.assertEqual(a.load({}), {})
437        self.assertEqual(a.load({'piwo': 'zlew'}), {Piwo(): Zlew()})
438        with self.assertRaises(SchemaError):
439            a.validate(a.load([]))
440        with self.assertRaises(SchemaError):
441            a.validate(a.load(None))
442        with self.assertRaises(SchemaError):
443            a.validate(a.load('piwo'))
444        with self.assertRaises(SchemaError):
445            a.validate(a.load({'piwo': 'piwo'}))
446        with self.assertRaises(SchemaError):
447            a.validate(a.load({'piwo', 'zlew'}))
448        self.assertEqual(a.dump({}), {})
449        self.assertEqual(a.dump({Piwo(): Zlew()}), {'piwo': 'zlew'})
450        fields.Map(fields.Integer(), fields.String(), default={1: 'a'})
451
452    def test_enum(self):
453        a = fields.Enum(ZlewType)
454        a.validate(ZlewType.ZLEW)
455        with self.assertRaises(SchemaError):
456            a.validate('ZLEW')
457        with self.assertRaises(SchemaError):
458            a.validate('zlewzlewzlew')
459        self.assertEqual(a.dump(ZlewType.ZLEW), 'ZLEW')
460        self.assertIsInstance(a.dump(ZlewType.ZLEW), six.text_type)
461        self.assertIs(a.load('TURBOZLEW'), ZlewType.TURBOZLEW)
462        with self.assertRaises(SchemaError):
463            a.load(2)
464        with self.assertRaises(SchemaError):
465            a.load('zlewzlewzlew')
466        with self.assertRaises(SchemaError):
467            a.load('PIETROZLEW')
468        with self.assertRaises(TypeError):
469            fields.Enum(int)
470
471    def test_exception(self):
472        a = fields.Object(VelesException)
473        a.validate(VelesException('abc', 'def'))
474        a.validate(SchemaError())
475        with self.assertRaises(SchemaError):
476            a.validate('zlew')
477        with self.assertRaises(SchemaError):
478            a.validate(Exception())
479        de = a.dump(VelesException('abc', 'def'))
480        self.assertEqual(de, {
481            'type': 'abc',
482            'message': 'def',
483        })
484        for k, v in de.items():
485            self.assertIsInstance(k, six.text_type)
486            self.assertIsInstance(v, six.text_type)
487        de = a.dump(SchemaError())
488        self.assertEqual(de, {
489            'type': 'schema_error',
490            'message': SchemaError.msg,
491        })
492        for k, v in de.items():
493            self.assertIsInstance(k, six.text_type)
494            self.assertIsInstance(v, six.text_type)
495        exc = a.load({
496            'type': 'abc',
497            'message': 'def',
498        })
499        self.assertIs(type(exc), VelesException)
500        self.assertEqual(exc.code, 'abc')
501        self.assertEqual(exc.msg, 'def')
502        exc = a.load({
503            'type': 'schema_error',
504            'message': 'ghi',
505        })
506        self.assertIs(type(exc), SchemaError)
507        self.assertEqual(exc.code, 'schema_error')
508        self.assertEqual(exc.msg, 'ghi')
509        with self.assertRaises(SchemaError):
510            a.load([])
511        with self.assertRaises(SchemaError):
512            a.load({})
513        with self.assertRaises(SchemaError):
514            a.load({'type': 'abc', 'message': 'def', 'hgw': 'zlew'})
515        with self.assertRaises(SchemaError):
516            a.load({'type': b'zlew', 'message': 'def'})
517        with self.assertRaises(SchemaError):
518            a.load({'type': 'zlew', 'message': b'def'})
519