source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/gluon/packages/dal/tests/validators.py

main
Last change on this file was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100755
File size: 66.1 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""Unit tests for http.py """
5
6import unittest
7import datetime
8import decimal
9import re
10
11from pydal import DAL, Field
12from pydal.validators import *
13from pydal._compat import PY2, to_bytes
14from pydal.validators import options_sorter, Validator, UTC
15
16
17class TestValidators(unittest.TestCase):
18    def myassertRegex(self, *args, **kwargs):
19        if PY2:
20            return getattr(self, "assertRegexpMatches")(*args, **kwargs)
21        return getattr(self, "assertRegex")(*args, **kwargs)
22
23    def test_MISC(self):
24        """ Test miscelaneous utility functions and some general behavior guarantees """
25
26        self.assertEqual(options_sorter(("a", "a"), ("a", "a")), -1)
27        self.assertEqual(options_sorter(("A", "A"), ("a", "a")), -1)
28        self.assertEqual(options_sorter(("b", "b"), ("a", "a")), 1)
29        self.assertRaises(NotImplementedError, Validator(), 1)
30        utc = UTC()
31        dt = datetime.datetime.now()
32        self.assertEqual(utc.utcoffset(dt), UTC.ZERO)
33        self.assertEqual(utc.dst(dt), UTC.ZERO)
34        self.assertEqual(utc.tzname(dt), "UTC")
35
36    def test_IS_MATCH(self):
37        rtn = IS_MATCH(".+")("hello")
38        self.assertEqual(rtn, ("hello", None))
39        rtn = IS_MATCH("hell")("hello")
40        self.assertEqual(rtn, ("hello", None))
41        rtn = IS_MATCH("hell.*", strict=False)("hello")
42        self.assertEqual(rtn, ("hello", None))
43        rtn = IS_MATCH("hello")("shello")
44        self.assertEqual(rtn, ("shello", "Invalid expression"))
45        rtn = IS_MATCH("hello", search=True)("shello")
46        self.assertEqual(rtn, ("shello", None))
47        rtn = IS_MATCH("hello", search=True, strict=False)("shellox")
48        self.assertEqual(rtn, ("shellox", None))
49        rtn = IS_MATCH(".*hello.*", search=True, strict=False)("shellox")
50        self.assertEqual(rtn, ("shellox", None))
51        rtn = IS_MATCH(".+")("")
52        self.assertEqual(rtn, ("", "Invalid expression"))
53        rtn = IS_MATCH("hell", strict=True)("hellas")
54        self.assertEqual(rtn, ("hellas", "Invalid expression"))
55        rtn = IS_MATCH("hell$", strict=True)("hellas")
56        self.assertEqual(rtn, ("hellas", "Invalid expression"))
57        rtn = IS_MATCH("^.hell$", strict=True)("shell")
58        self.assertEqual(rtn, ("shell", None))
59        rtn = IS_MATCH(u"hell", is_unicode=True)("àòè")
60        if PY2:
61            self.assertEqual(rtn, ("\xc3\xa0\xc3\xb2\xc3\xa8", "Invalid expression"))
62        else:
63            self.assertEqual(rtn, ("àòè", "Invalid expression"))
64        rtn = IS_MATCH(u"hell", is_unicode=True)(u"hell")
65        self.assertEqual(rtn, (u"hell", None))
66        rtn = IS_MATCH("hell", is_unicode=True)(u"hell")
67        self.assertEqual(rtn, (u"hell", None))
68        # regr test for #1044
69        rtn = IS_MATCH("hello")(u"\xff")
70        self.assertEqual(rtn, (u"\xff", "Invalid expression"))
71
72    def test_IS_EQUAL_TO(self):
73        rtn = IS_EQUAL_TO("aaa")("aaa")
74        self.assertEqual(rtn, ("aaa", None))
75        rtn = IS_EQUAL_TO("aaa")("aab")
76        self.assertEqual(rtn, ("aab", "No match"))
77
78    def test_IS_EXPR(self):
79        rtn = IS_EXPR("int(value) < 2")("1")
80        self.assertEqual(rtn, ("1", None))
81        rtn = IS_EXPR("int(value) < 2")("2")
82        self.assertEqual(rtn, ("2", "Invalid expression"))
83        rtn = IS_EXPR(lambda value: int(value))("1")
84        self.assertEqual(rtn, ("1", 1))
85        rtn = IS_EXPR(lambda value: int(value) < 2 and "invalid" or None)("2")
86        self.assertEqual(rtn, ("2", None))
87
88    def test_IS_LENGTH(self):
89        rtn = IS_LENGTH()("")
90        self.assertEqual(rtn, ("", None))
91        rtn = IS_LENGTH()("1234567890")
92        self.assertEqual(rtn, ("1234567890", None))
93        rtn = IS_LENGTH(maxsize=5, minsize=0)("1234567890")  # too long
94        self.assertEqual(rtn, ("1234567890", "Enter from 0 to 5 characters"))
95        rtn = IS_LENGTH(maxsize=50, minsize=20)("1234567890")  # too short
96        self.assertEqual(rtn, ("1234567890", "Enter from 20 to 50 characters"))
97        rtn = IS_LENGTH()(None)
98        self.assertEqual(rtn, (None, None))
99        rtn = IS_LENGTH(minsize=0)(None)
100        self.assertEqual(rtn, (None, None))
101        rtn = IS_LENGTH(minsize=1)(None)
102        self.assertEqual(rtn, (None, "Enter from 1 to 255 characters"))
103        rtn = IS_LENGTH(minsize=1)([])
104        self.assertEqual(rtn, ([], "Enter from 1 to 255 characters"))
105        rtn = IS_LENGTH(minsize=1)([1, 2])
106        self.assertEqual(rtn, ([1, 2], None))
107        rtn = IS_LENGTH(minsize=1)([1])
108        self.assertEqual(rtn, ([1], None))
109        # test non utf-8 str
110        cpstr = u"lálá".encode("cp1252")
111        rtn = IS_LENGTH(minsize=4)(cpstr)
112        self.assertEqual(rtn, (cpstr, None))
113        rtn = IS_LENGTH(maxsize=4)(cpstr)
114        self.assertEqual(rtn, (cpstr, None))
115        rtn = IS_LENGTH(minsize=0, maxsize=3)(cpstr)
116        self.assertEqual(rtn, (cpstr, "Enter from 0 to 3 characters"))
117        # test unicode
118        rtn = IS_LENGTH(2)(u"°2")
119        if PY2:
120            self.assertEqual(rtn, ("\xc2\xb02", None))
121        else:
122            self.assertEqual(rtn, (u"°2", None))
123        rtn = IS_LENGTH(2)(u"°12")
124        if PY2:
125            self.assertEqual(rtn, (u"\xb012", "Enter from 0 to 2 characters"))
126        else:
127            self.assertEqual(rtn, (u"°12", "Enter from 0 to 2 characters"))
128        # test automatic str()
129        rtn = IS_LENGTH(minsize=1)(1)
130        self.assertEqual(rtn, ("1", None))
131        rtn = IS_LENGTH(minsize=2)(1)
132        self.assertEqual(rtn, (1, "Enter from 2 to 255 characters"))
133        # test FieldStorage
134        import cgi
135        from io import BytesIO
136
137        a = cgi.FieldStorage()
138        a.file = BytesIO(b"abc")
139        rtn = IS_LENGTH(minsize=4)(a)
140        self.assertEqual(rtn, (a, "Enter from 4 to 255 characters"))
141        urlencode_data = b"key2=value2x&key3=value3&key4=value4"
142        urlencode_environ = {
143            "CONTENT_LENGTH": str(len(urlencode_data)),
144            "CONTENT_TYPE": "application/x-www-form-urlencoded",
145            "QUERY_STRING": "key1=value1&key2=value2y",
146            "REQUEST_METHOD": "POST",
147        }
148        fake_stdin = BytesIO(urlencode_data)
149        fake_stdin.seek(0)
150        a = cgi.FieldStorage(fp=fake_stdin, environ=urlencode_environ)
151        rtn = IS_LENGTH(minsize=6)(a)
152        self.assertEqual(rtn, (a, "Enter from 6 to 255 characters"))
153        a = cgi.FieldStorage()
154        rtn = IS_LENGTH(minsize=6)(a)
155        self.assertEqual(rtn, (a, "Enter from 6 to 255 characters"))
156        rtn = IS_LENGTH(6)(a)
157        self.assertEqual(rtn, (a, None))
158
159    def test_IS_JSON(self):
160        rtn = IS_JSON()('{"a": 100}')
161        self.assertEqual(rtn, ({u"a": 100}, None))
162        rtn = IS_JSON()("spam1234")
163        self.assertEqual(rtn, ("spam1234", "Invalid json"))
164        rtn = IS_JSON(native_json=True)('{"a": 100}')
165        self.assertEqual(rtn, ('{"a": 100}', None))
166        rtn = IS_JSON().formatter(None)
167        self.assertEqual(rtn, None)
168        rtn = IS_JSON().formatter({"a": 100})
169        self.assertEqual(rtn, '{"a": 100}')
170        rtn = IS_JSON(native_json=True).formatter({"a": 100})
171        self.assertEqual(rtn, {"a": 100})
172
173    def test_IS_IN_SET(self):
174        rtn = IS_IN_SET(["max", "john"])("max")
175        self.assertEqual(rtn, ("max", None))
176        rtn = IS_IN_SET(["max", "john"])("massimo")
177        self.assertEqual(rtn, ("massimo", "Value not allowed"))
178        rtn = IS_IN_SET(["max", "john"], multiple=True)(("max", "john"))
179        self.assertEqual(rtn, (("max", "john"), None))
180        rtn = IS_IN_SET(["max", "john"], multiple=True)(("bill", "john"))
181        self.assertEqual(rtn, (("bill", "john"), "Value not allowed"))
182        rtn = IS_IN_SET(("id1", "id2"), ["first label", "second label"])(
183            "id1"
184        )  # Traditional way
185        self.assertEqual(rtn, ("id1", None))
186        rtn = IS_IN_SET({"id1": "first label", "id2": "second label"})("id1")
187        self.assertEqual(rtn, ("id1", None))
188        rtn = IS_IN_SET(["id1", "id2"], error_message="oops", multiple=True)(None)
189        self.assertEqual(rtn, ([], None))
190        rtn = IS_IN_SET(["id1", "id2"], error_message="oops", multiple=True)("")
191        self.assertEqual(rtn, ([], None))
192        rtn = IS_IN_SET(["id1", "id2"], error_message="oops", multiple=True)("id1")
193        self.assertEqual(rtn, (["id1"], None))
194        rtn = IS_IN_SET(["id1", "id2"], error_message="oops", multiple=(1, 2))(None)
195        self.assertEqual(rtn, (None, "oops"))
196        import itertools
197
198        rtn = IS_IN_SET(itertools.chain(["1", "3", "5"], ["2", "4", "6"]))("1")
199        self.assertEqual(rtn, ("1", None))
200        rtn = IS_IN_SET([("id1", "first label"), ("id2", "second label")])(
201            "id1"
202        )  # Redundant way
203        self.assertEqual(rtn, ("id1", None))
204        rtn = IS_IN_SET([("id1", "first label"), ("id2", "second label")]).options(
205            zero=False
206        )
207        self.assertEqual(rtn, [("id1", "first label"), ("id2", "second label")])
208        rtn = IS_IN_SET(["id1", "id2"]).options(zero=False)
209        self.assertEqual(rtn, [("id1", "id1"), ("id2", "id2")])
210        rtn = IS_IN_SET(["id2", "id1"], sort=True).options(zero=False)
211        self.assertEqual(rtn, [("id1", "id1"), ("id2", "id2")])
212
213    def test_IS_IN_DB(self):
214        db = DAL("sqlite:memory")
215        db.define_table("person", Field("name"))
216        george_id = db.person.insert(name="george")
217        costanza_id = db.person.insert(name="costanza")
218        rtn = IS_IN_DB(db, "person.id", "%(name)s")(george_id)
219        self.assertEqual(rtn, (george_id, None))
220        rtn = IS_IN_DB(db, "person.name", "%(name)s")("george")
221        self.assertEqual(rtn, ("george", None))
222        rtn = IS_IN_DB(db, db.person, "%(name)s")(george_id)
223        self.assertEqual(rtn, (george_id, None))
224        rtn = IS_IN_DB(db(db.person.id > 0), db.person, "%(name)s")(george_id)
225        self.assertEqual(rtn, (george_id, None))
226        rtn = IS_IN_DB(db, "person.id", "%(name)s", error_message="oops")(
227            george_id + costanza_id
228        )
229        self.assertEqual(rtn, (george_id + costanza_id, "oops"))
230        rtn = IS_IN_DB(db, db.person.id, "%(name)s")(george_id)
231        self.assertEqual(rtn, (george_id, None))
232        rtn = IS_IN_DB(db, db.person.id, "%(name)s", error_message="oops")(
233            george_id + costanza_id
234        )
235        self.assertEqual(rtn, (george_id + costanza_id, "oops"))
236        rtn = IS_IN_DB(db, "person.id", "%(name)s", multiple=True)(
237            [george_id, costanza_id]
238        )
239        self.assertEqual(rtn, ([george_id, costanza_id], None))
240        rtn = IS_IN_DB(
241            db, "person.id", "%(name)s", multiple=True, error_message="oops"
242        )("I'm not even an id")
243        self.assertEqual(rtn, ("I'm not even an id", "oops"))
244        rtn = IS_IN_DB(db, "person.id", "%(name)s", multiple=True, delimiter=",")(
245            "%d,%d" % (george_id, costanza_id)
246        )
247        self.assertEqual(rtn, (("%d,%d" % (george_id, costanza_id)).split(","), None))
248        rtn = IS_IN_DB(db, "person.id", "%(name)s", multiple=(1, 3), delimiter=",")(
249            "%d,%d" % (george_id, costanza_id)
250        )
251        self.assertEqual(rtn, (("%d,%d" % (george_id, costanza_id)).split(","), None))
252        rtn = IS_IN_DB(
253            db,
254            "person.id",
255            "%(name)s",
256            multiple=(1, 2),
257            delimiter=",",
258            error_message="oops",
259        )("%d,%d" % (george_id, costanza_id))
260        self.assertEqual(rtn, (("%d,%d" % (george_id, costanza_id)), "oops"))
261        rtn = IS_IN_DB(db, db.person.id, "%(name)s", error_message="oops").options(
262            zero=False
263        )
264        self.assertEqual(
265            sorted(rtn),
266            [("%d" % george_id, "george"), ("%d" % costanza_id, "costanza")],
267        )
268        rtn = IS_IN_DB(
269            db, db.person.id, db.person.name, error_message="oops", sort=True
270        ).options(zero=True)
271        self.assertEqual(
272            rtn,
273            [("", ""), ("%d" % costanza_id, "costanza"), ("%d" % george_id, "george")],
274        )
275        # Test None
276        rtn = IS_IN_DB(db, "person.id", "%(name)s", error_message="oops")(None)
277        self.assertEqual(rtn, (None, "oops"))
278        rtn = IS_IN_DB(db, "person.name", "%(name)s", error_message="oops")(None)
279        self.assertEqual(rtn, (None, "oops"))
280        # Test using the set it made for options
281        vldtr = IS_IN_DB(db, "person.name", "%(name)s", error_message="oops")
282        vldtr.options()
283        rtn = vldtr("george")
284        self.assertEqual(rtn, ("george", None))
285        rtn = vldtr("jerry")
286        self.assertEqual(rtn, ("jerry", "oops"))
287        vldtr = IS_IN_DB(
288            db, "person.name", "%(name)s", error_message="oops", multiple=True
289        )
290        vldtr.options()
291        rtn = vldtr(["george", "costanza"])
292        self.assertEqual(rtn, (["george", "costanza"], None))
293        # Test it works with self reference
294        db.define_table(
295            "category",
296            Field(
297                "parent_id",
298                "reference category",
299                requires=IS_EMPTY_OR(IS_IN_DB(db, "category.id", "%(name)s")),
300            ),
301            Field("name"),
302        )
303        ret = db.category.validate_and_insert(name="seinfeld")
304        self.assertFalse(list(ret.errors))
305        ret = db.category.validate_and_insert(name="characters", parent_id=ret.id)
306        self.assertFalse(list(ret.errors))
307        rtn = IS_IN_DB(db, "category.id", "%(name)s")(ret.id)
308        self.assertEqual(rtn, (ret.id, None))
309        # Test _and
310        vldtr = IS_IN_DB(
311            db,
312            "person.name",
313            "%(name)s",
314            error_message="oops",
315            _and=IS_LENGTH(maxsize=7, error_message="bad"),
316        )
317        rtn = vldtr("george")
318        self.assertEqual(rtn, ("george", None))
319        rtn = vldtr("costanza")
320        self.assertEqual(rtn, ("costanza", "bad"))
321        rtn = vldtr("jerry")
322        self.assertEqual(rtn, ("jerry", "oops"))
323        vldtr.options()  # test theset with _and
324        rtn = vldtr("jerry")
325        self.assertEqual(rtn, ("jerry", "oops"))
326        # Test auto_add
327        rtn = IS_IN_DB(db, "person.id", "%(name)s", error_message="oops")("jerry")
328        self.assertEqual(rtn, ("jerry", "oops"))
329        rtn = IS_IN_DB(db, "person.id", "%(name)s", auto_add=True)("jerry")
330        self.assertEqual(rtn, (3, None))
331        # Test it works with reference table
332        db.define_table(
333            "ref_table", Field("name"), Field("person_id", "reference person")
334        )
335        ret = db.ref_table.validate_and_insert(name="test reference table")
336        self.assertFalse(list(ret.errors))
337        ret = db.ref_table.validate_and_insert(
338            name="test reference table", person_id=george_id
339        )
340        self.assertFalse(list(ret.errors))
341        rtn = IS_IN_DB(db, "ref_table.person_id", "%(name)s")(george_id)
342        self.assertEqual(rtn, (george_id, None))
343        # Test it works with reference table.field and keyed table
344        db.define_table("person_keyed", Field("name"), primarykey=["name"])
345        db.person_keyed.insert(name="george")
346        db.person_keyed.insert(name="costanza")
347        rtn = IS_IN_DB(db, "person_keyed.name")("george")
348        self.assertEqual(rtn, ("george", None))
349        db.define_table(
350            "ref_table_field",
351            Field("name"),
352            Field("person_name", "reference person_keyed.name"),
353        )
354        ret = db.ref_table_field.validate_and_insert(name="test reference table.field")
355        self.assertFalse(list(ret.errors))
356        ret = db.ref_table_field.validate_and_insert(
357            name="test reference table.field", person_name="george"
358        )
359        self.assertFalse(list(ret.errors))
360        vldtr = IS_IN_DB(db, "ref_table_field.person_name", "%(name)s")
361        vldtr.options()
362        rtn = vldtr("george")
363        self.assertEqual(rtn, ("george", None))
364        # Test it works with list:reference table
365        db.define_table(
366            "list_ref_table",
367            Field("name"),
368            Field("person_list", "list:reference person"),
369        )
370        ret = db.list_ref_table.validate_and_insert(name="test list:reference table")
371        self.assertFalse(list(ret.errors))
372        ret = db.list_ref_table.validate_and_insert(
373            name="test list:reference table", person_list=[george_id, costanza_id]
374        )
375        self.assertFalse(list(ret.errors))
376        vldtr = IS_IN_DB(db, "list_ref_table.person_list")
377        vldtr.options()
378        rtn = vldtr([george_id, costanza_id])
379        self.assertEqual(rtn, ([george_id, costanza_id], None))
380        # Test it works with list:reference table.field and keyed table
381        # db.define_table('list_ref_table_field',
382        #                Field('name'),
383        #                Field('person_list', 'list:reference person_keyed.name'))
384        # ret = db.list_ref_table_field.validate_and_insert(name='test list:reference table.field')
385        # self.assertFalse(list(ret.errors))
386        # ret = db.list_ref_table_field.validate_and_insert(name='test list:reference table.field', person_list=['george','costanza'])
387        # self.assertFalse(list(ret.errors))
388        # vldtr = IS_IN_DB(db, 'list_ref_table_field.person_list')
389        # vldtr.options()
390        # rtn = vldtr(['george','costanza'])
391        # self.assertEqual(rtn, (['george','costanza'], None))
392        db.person.drop()
393        db.category.drop()
394        db.person_keyed.drop()
395        db.ref_table.drop()
396        db.ref_table_field.drop()
397        db.list_ref_table.drop()
398        # db.list_ref_table_field.drop()
399
400    def test_IS_NOT_IN_DB(self):
401        db = DAL("sqlite:memory")
402        db.define_table("person", Field("name"), Field("nickname"))
403        db.person.insert(name="george")
404        db.person.insert(name="costanza", nickname="T Bone")
405        rtn = IS_NOT_IN_DB(db, "person.name", error_message="oops")("george")
406        self.assertEqual(rtn, ("george", "oops"))
407        rtn = IS_NOT_IN_DB(
408            db, "person.name", error_message="oops", allowed_override=["george"]
409        )("george")
410        self.assertEqual(rtn, ("george", None))
411        rtn = IS_NOT_IN_DB(db, "person.name", error_message="oops")("  ")
412        self.assertEqual(rtn, ("  ", "oops"))
413        rtn = IS_NOT_IN_DB(db, "person.name")("jerry")
414        self.assertEqual(rtn, ("jerry", None))
415        rtn = IS_NOT_IN_DB(db, "person.name")(u"jerry")
416        self.assertEqual(rtn, ("jerry", None))
417        rtn = IS_NOT_IN_DB(db(db.person.id > 0), "person.name")(u"jerry")
418        self.assertEqual(rtn, ("jerry", None))
419        rtn = IS_NOT_IN_DB(db, db.person, error_message="oops")(1)
420        self.assertEqual(rtn, (1, "oops"))
421        vldtr = IS_NOT_IN_DB(db, "person.name", error_message="oops")
422        vldtr.set_self_id({"name": "costanza", "nickname": "T Bone"})
423        rtn = vldtr("george")
424        self.assertEqual(rtn, ("george", "oops"))
425        rtn = vldtr("costanza")
426        self.assertEqual(rtn, ("costanza", None))
427
428        db.person.drop()
429
430    def test_IS_INT_IN_RANGE(self):
431        rtn = IS_INT_IN_RANGE(1, 5)("4")
432        self.assertEqual(rtn, (4, None))
433        rtn = IS_INT_IN_RANGE(1, 5)(4)
434        self.assertEqual(rtn, (4, None))
435        rtn = IS_INT_IN_RANGE(1, 5)(1)
436        self.assertEqual(rtn, (1, None))
437        rtn = IS_INT_IN_RANGE(1, 5)(5)
438        self.assertEqual(rtn, (5, "Enter an integer between 1 and 4"))
439        rtn = IS_INT_IN_RANGE(1, 5)(5)
440        self.assertEqual(rtn, (5, "Enter an integer between 1 and 4"))
441        rtn = IS_INT_IN_RANGE(1, 5)(3.5)
442        self.assertEqual(rtn, (3.5, "Enter an integer between 1 and 4"))
443        rtn = IS_INT_IN_RANGE(None, 5)("4")
444        self.assertEqual(rtn, (4, None))
445        rtn = IS_INT_IN_RANGE(None, 5)("6")
446        self.assertEqual(rtn, ("6", "Enter an integer less than or equal to 4"))
447        rtn = IS_INT_IN_RANGE(1, None)("4")
448        self.assertEqual(rtn, (4, None))
449        rtn = IS_INT_IN_RANGE(1, None)("0")
450        self.assertEqual(rtn, ("0", "Enter an integer greater than or equal to 1"))
451        rtn = IS_INT_IN_RANGE()(6)
452        self.assertEqual(rtn, (6, None))
453        rtn = IS_INT_IN_RANGE()("abc")
454        self.assertEqual(rtn, ("abc", "Enter an integer"))
455
456    def test_IS_FLOAT_IN_RANGE(self):
457        # with None
458        rtn = IS_FLOAT_IN_RANGE(1, 5)(None)
459        self.assertEqual(rtn, (None, "Enter a number between 1 and 5"))
460        rtn = IS_FLOAT_IN_RANGE(1, 5)("4")
461        self.assertEqual(rtn, (4.0, None))
462        rtn = IS_FLOAT_IN_RANGE(1, 5)(4)
463        self.assertEqual(rtn, (4.0, None))
464        rtn = IS_FLOAT_IN_RANGE(1, 5)(1)
465        self.assertEqual(rtn, (1.0, None))
466        rtn = IS_FLOAT_IN_RANGE(1, 5)(5.25)
467        self.assertEqual(rtn, (5.25, "Enter a number between 1 and 5"))
468        rtn = IS_FLOAT_IN_RANGE(1, 5)(6.0)
469        self.assertEqual(rtn, (6.0, "Enter a number between 1 and 5"))
470        rtn = IS_FLOAT_IN_RANGE(1, 5)(3.5)
471        self.assertEqual(rtn, (3.5, None))
472        rtn = IS_FLOAT_IN_RANGE(1, None)(3.5)
473        self.assertEqual(rtn, (3.5, None))
474        rtn = IS_FLOAT_IN_RANGE(None, 5)(3.5)
475        self.assertEqual(rtn, (3.5, None))
476        rtn = IS_FLOAT_IN_RANGE(1, None)(0.5)
477        self.assertEqual(rtn, (0.5, "Enter a number greater than or equal to 1"))
478        rtn = IS_FLOAT_IN_RANGE(None, 5)(6.5)
479        self.assertEqual(rtn, (6.5, "Enter a number less than or equal to 5"))
480        rtn = IS_FLOAT_IN_RANGE()(6.5)
481        self.assertEqual(rtn, (6.5, None))
482        rtn = IS_FLOAT_IN_RANGE()("abc")
483        self.assertEqual(rtn, ("abc", "Enter a number"))
484        rtn = IS_FLOAT_IN_RANGE()("6,5")
485        self.assertEqual(rtn, ("6,5", "Enter a number"))
486        rtn = IS_FLOAT_IN_RANGE(dot=",")("6.5")
487        self.assertEqual(rtn, (6.5, None))
488        # With .formatter(None)
489        rtn = IS_FLOAT_IN_RANGE(dot=",").formatter(None)
490        self.assertEqual(rtn, None)
491        rtn = IS_FLOAT_IN_RANGE(dot=",").formatter(0.25)
492        self.assertEqual(rtn, "0,25")
493        # To trigger str2dec "if not '.' in s:" line
494        rtn = IS_FLOAT_IN_RANGE(dot=",").formatter(1)
495        self.assertEqual(rtn, "1,00")
496
497    def test_IS_DECIMAL_IN_RANGE(self):
498        # with None
499        rtn = IS_DECIMAL_IN_RANGE(1, 5)(None)
500        self.assertEqual(rtn, (None, "Enter a number between 1 and 5"))
501        rtn = IS_DECIMAL_IN_RANGE(1, 5)("4")
502        self.assertEqual(rtn, (decimal.Decimal("4"), None))
503        rtn = IS_DECIMAL_IN_RANGE(1, 5)(4)
504        self.assertEqual(rtn, (decimal.Decimal("4"), None))
505        rtn = IS_DECIMAL_IN_RANGE(1, 5)(1)
506        self.assertEqual(rtn, (decimal.Decimal("1"), None))
507        rtn = IS_DECIMAL_IN_RANGE(1, 5)(5.25)
508        self.assertEqual(rtn, (5.25, "Enter a number between 1 and 5"))
509        rtn = IS_DECIMAL_IN_RANGE(5.25, 6)(5.25)
510        self.assertEqual(rtn, (decimal.Decimal("5.25"), None))
511        rtn = IS_DECIMAL_IN_RANGE(5.25, 6)("5.25")
512        self.assertEqual(rtn, (decimal.Decimal("5.25"), None))
513        rtn = IS_DECIMAL_IN_RANGE(1, 5)(6.0)
514        self.assertEqual(rtn, (6.0, "Enter a number between 1 and 5"))
515        rtn = IS_DECIMAL_IN_RANGE(1, 5)(3.5)
516        self.assertEqual(rtn, (decimal.Decimal("3.5"), None))
517        rtn = IS_DECIMAL_IN_RANGE(1.5, 5.5)(3.5)
518        self.assertEqual(rtn, (decimal.Decimal("3.5"), None))
519        rtn = IS_DECIMAL_IN_RANGE(1.5, 5.5)(6.5)
520        self.assertEqual(rtn, (6.5, "Enter a number between 1.5 and 5.5"))
521        rtn = IS_DECIMAL_IN_RANGE(1.5, None)(6.5)
522        self.assertEqual(rtn, (decimal.Decimal("6.5"), None))
523        rtn = IS_DECIMAL_IN_RANGE(1.5, None)(0.5)
524        self.assertEqual(rtn, (0.5, "Enter a number greater than or equal to 1.5"))
525        rtn = IS_DECIMAL_IN_RANGE(None, 5.5)(4.5)
526        self.assertEqual(rtn, (decimal.Decimal("4.5"), None))
527        rtn = IS_DECIMAL_IN_RANGE(None, 5.5)(6.5)
528        self.assertEqual(rtn, (6.5, "Enter a number less than or equal to 5.5"))
529        rtn = IS_DECIMAL_IN_RANGE()(6.5)
530        self.assertEqual(rtn, (decimal.Decimal("6.5"), None))
531        rtn = IS_DECIMAL_IN_RANGE(0, 99)(123.123)
532        self.assertEqual(rtn, (123.123, "Enter a number between 0 and 99"))
533        rtn = IS_DECIMAL_IN_RANGE(0, 99)("123.123")
534        self.assertEqual(rtn, ("123.123", "Enter a number between 0 and 99"))
535        rtn = IS_DECIMAL_IN_RANGE(0, 99)("12.34")
536        self.assertEqual(rtn, (decimal.Decimal("12.34"), None))
537        rtn = IS_DECIMAL_IN_RANGE()("abc")
538        self.assertEqual(rtn, ("abc", "Enter a number"))
539        rtn = IS_DECIMAL_IN_RANGE()("6,5")
540        self.assertEqual(rtn, ("6,5", "Enter a number"))
541        rtn = IS_DECIMAL_IN_RANGE(dot=",")("6.5")
542        self.assertEqual(rtn, (decimal.Decimal("6.5"), None))
543        rtn = IS_DECIMAL_IN_RANGE(1, 5)(decimal.Decimal("4"))
544        self.assertEqual(rtn, (decimal.Decimal("4"), None))
545        # With .formatter(None)
546        rtn = IS_DECIMAL_IN_RANGE(dot=",").formatter(None)
547        self.assertEqual(rtn, None)
548        rtn = IS_DECIMAL_IN_RANGE(dot=",").formatter(0.25)
549        self.assertEqual(rtn, "0,25")
550
551    def test_IS_NOT_EMPTY(self):
552        rtn = IS_NOT_EMPTY()(1)
553        self.assertEqual(rtn, (1, None))
554        rtn = IS_NOT_EMPTY()(0)
555        self.assertEqual(rtn, (0, None))
556        rtn = IS_NOT_EMPTY()("x")
557        self.assertEqual(rtn, ("x", None))
558        rtn = IS_NOT_EMPTY()(" x ")
559        self.assertEqual(rtn, (" x ", None))
560        rtn = IS_NOT_EMPTY()(None)
561        self.assertEqual(rtn, (None, "Enter a value"))
562        rtn = IS_NOT_EMPTY()("")
563        self.assertEqual(rtn, ("", "Enter a value"))
564        rtn = IS_NOT_EMPTY()(b"")
565        self.assertEqual(rtn, (b"", "Enter a value"))
566        rtn = IS_NOT_EMPTY()("  ")
567        self.assertEqual(rtn, ("  ", "Enter a value"))
568        rtn = IS_NOT_EMPTY()(" \n\t")
569        self.assertEqual(rtn, (" \n\t", "Enter a value"))
570        rtn = IS_NOT_EMPTY()([])
571        self.assertEqual(rtn, ([], "Enter a value"))
572        rtn = IS_NOT_EMPTY(empty_regex="def")("def")
573        self.assertEqual(rtn, ("def", "Enter a value"))
574        rtn = IS_NOT_EMPTY(empty_regex="de[fg]")("deg")
575        self.assertEqual(rtn, ("deg", "Enter a value"))
576        rtn = IS_NOT_EMPTY(empty_regex="def")("abc")
577        self.assertEqual(rtn, ("abc", None))
578
579    def test_IS_ALPHANUMERIC(self):
580        rtn = IS_ALPHANUMERIC()("1")
581        self.assertEqual(rtn, ("1", None))
582        rtn = IS_ALPHANUMERIC()("")
583        self.assertEqual(rtn, ("", None))
584        rtn = IS_ALPHANUMERIC()("A_a")
585        self.assertEqual(rtn, ("A_a", None))
586        rtn = IS_ALPHANUMERIC()("!")
587        self.assertEqual(rtn, ("!", "Enter only letters, numbers, and underscore"))
588
589    def test_IS_EMAIL(self):
590        rtn = IS_EMAIL()("a@b.com")
591        self.assertEqual(rtn, ("a@b.com", None))
592        rtn = IS_EMAIL()("abc@def.com")
593        self.assertEqual(rtn, ("abc@def.com", None))
594        rtn = IS_EMAIL()("abc@3def.com")
595        self.assertEqual(rtn, ("abc@3def.com", None))
596        rtn = IS_EMAIL()("abc@def.us")
597        self.assertEqual(rtn, ("abc@def.us", None))
598        rtn = IS_EMAIL()("abc@d_-f.us")
599        self.assertEqual(rtn, ("abc@d_-f.us", None))
600        rtn = IS_EMAIL()("@def.com")  # missing name
601        self.assertEqual(rtn, ("@def.com", "Enter a valid email address"))
602        rtn = IS_EMAIL()('"abc@def".com')  # quoted name
603        self.assertEqual(rtn, ('"abc@def".com', "Enter a valid email address"))
604        rtn = IS_EMAIL()("abc+def.com")  # no @
605        self.assertEqual(rtn, ("abc+def.com", "Enter a valid email address"))
606        rtn = IS_EMAIL()("abc@def.x")  # one-char TLD
607        self.assertEqual(rtn, ("abc@def.x", "Enter a valid email address"))
608        rtn = IS_EMAIL()("abc@def.12")  # numeric TLD
609        self.assertEqual(rtn, ("abc@def.12", "Enter a valid email address"))
610        rtn = IS_EMAIL()("abc@def..com")  # double-dot in domain
611        self.assertEqual(rtn, ("abc@def..com", "Enter a valid email address"))
612        rtn = IS_EMAIL()("abc@.def.com")  # dot starts domain
613        self.assertEqual(rtn, ("abc@.def.com", "Enter a valid email address"))
614        rtn = IS_EMAIL()("abc@def.c_m")  # underscore in TLD
615        self.assertEqual(rtn, ("abc@def.c_m", "Enter a valid email address"))
616        rtn = IS_EMAIL()("NotAnEmail")  # missing @
617        self.assertEqual(rtn, ("NotAnEmail", "Enter a valid email address"))
618        rtn = IS_EMAIL()("abc@NotAnEmail")  # missing TLD
619        self.assertEqual(rtn, ("abc@NotAnEmail", "Enter a valid email address"))
620        rtn = IS_EMAIL()("customer/department@example.com")
621        self.assertEqual(rtn, ("customer/department@example.com", None))
622        rtn = IS_EMAIL()("$A12345@example.com")
623        self.assertEqual(rtn, ("$A12345@example.com", None))
624        rtn = IS_EMAIL()("!def!xyz%abc@example.com")
625        self.assertEqual(rtn, ("!def!xyz%abc@example.com", None))
626        rtn = IS_EMAIL()("_Yosemite.Sam@example.com")
627        self.assertEqual(rtn, ("_Yosemite.Sam@example.com", None))
628        rtn = IS_EMAIL()("~@example.com")
629        self.assertEqual(rtn, ("~@example.com", None))
630        rtn = IS_EMAIL()(".wooly@example.com")  # dot starts name
631        self.assertEqual(rtn, (".wooly@example.com", "Enter a valid email address"))
632        rtn = IS_EMAIL()("wo..oly@example.com")  # adjacent dots in name
633        self.assertEqual(rtn, ("wo..oly@example.com", "Enter a valid email address"))
634        rtn = IS_EMAIL()("pootietang.@example.com")  # dot ends name
635        self.assertEqual(
636            rtn, ("pootietang.@example.com", "Enter a valid email address")
637        )
638        rtn = IS_EMAIL()(".@example.com")  # name is bare dot
639        self.assertEqual(rtn, (".@example.com", "Enter a valid email address"))
640        rtn = IS_EMAIL()("Ima.Fool@example.com")
641        self.assertEqual(rtn, ("Ima.Fool@example.com", None))
642        rtn = IS_EMAIL()("Ima Fool@example.com")  # space in name
643        self.assertEqual(rtn, ("Ima Fool@example.com", "Enter a valid email address"))
644        rtn = IS_EMAIL()("localguy@localhost")  # localhost as domain
645        self.assertEqual(rtn, ("localguy@localhost", None))
646        # test for banned
647        rtn = IS_EMAIL(banned=r"^.*\.com(|\..*)$")(
648            "localguy@localhost"
649        )  # localhost as domain
650        self.assertEqual(rtn, ("localguy@localhost", None))
651        rtn = IS_EMAIL(banned=r"^.*\.com(|\..*)$")("abc@example.com")
652        self.assertEqual(rtn, ("abc@example.com", "Enter a valid email address"))
653        # test for forced
654        rtn = IS_EMAIL(forced="^.*\.edu(|\..*)$")("localguy@localhost")
655        self.assertEqual(rtn, ("localguy@localhost", "Enter a valid email address"))
656        rtn = IS_EMAIL(forced=r"^.*\.edu(|\..*)$")("localguy@example.edu")
657        self.assertEqual(rtn, ("localguy@example.edu", None))
658        # test for not a string at all
659        rtn = IS_EMAIL(error_message="oops")(42)
660        self.assertEqual(rtn, (42, "oops"))
661
662        # test for Internationalized Domain Names, see https://docs.python.org/2/library/codecs.html#module-encodings.idna
663        rtn = IS_EMAIL()("web2py@Alliancefrançaise.nu")
664        self.assertEqual(rtn, ("web2py@Alliancefrançaise.nu", None))
665
666    def test_IS_LIST_OF_EMAILS(self):
667        emails = ["localguy@localhost", "_Yosemite.Sam@example.com"]
668        rtn = IS_LIST_OF_EMAILS()(",".join(emails))
669        self.assertEqual(rtn, (",".join(emails), None))
670        rtn = IS_LIST_OF_EMAILS()(";".join(emails))
671        self.assertEqual(rtn, (";".join(emails), None))
672        rtn = IS_LIST_OF_EMAILS()(" ".join(emails))
673        self.assertEqual(rtn, (" ".join(emails), None))
674        emails.append("a")
675        rtn = IS_LIST_OF_EMAILS()(";".join(emails))
676        self.assertEqual(
677            rtn, ("localguy@localhost;_Yosemite.Sam@example.com;a", "Invalid emails: a")
678        )
679        rtn = IS_LIST_OF_EMAILS().formatter(["test@example.com", "dude@example.com"])
680        self.assertEqual(rtn, "test@example.com, dude@example.com")
681
682    def test_IS_URL(self):
683        rtn = IS_URL()("http://example.com")
684        self.assertEqual(rtn, ("http://example.com", None))
685        rtn = IS_URL(error_message="oops")("http://example,com")
686        self.assertEqual(rtn, ("http://example,com", "oops"))
687        rtn = IS_URL(error_message="oops")(
688            "http://www.example.com:8800/a/b/c/d/e/f/g/h"
689        )
690        self.assertEqual(rtn, ("http://www.example.com:8800/a/b/c/d/e/f/g/h", None))
691        rtn = IS_URL(error_message="oops", prepend_scheme="http")("example.com")
692        self.assertEqual(rtn, ("http://example.com", None))
693        rtn = IS_URL()("http://example.com?q=george&p=22")
694        self.assertEqual(rtn, ("http://example.com?q=george&p=22", None))
695        rtn = IS_URL(mode="generic", prepend_scheme=None)("example.com")
696        self.assertEqual(rtn, ("example.com", None))
697
698    def test_IS_TIME(self):
699        rtn = IS_TIME()("21:30")
700        self.assertEqual(rtn, (datetime.time(21, 30), None))
701        rtn = IS_TIME()("21-30")
702        self.assertEqual(rtn, (datetime.time(21, 30), None))
703        rtn = IS_TIME()("21.30")
704        self.assertEqual(rtn, (datetime.time(21, 30), None))
705        rtn = IS_TIME()("21:30:59")
706        self.assertEqual(rtn, (datetime.time(21, 30, 59), None))
707        rtn = IS_TIME()("5:30")
708        self.assertEqual(rtn, (datetime.time(5, 30), None))
709        rtn = IS_TIME()("5:30 am")
710        self.assertEqual(rtn, (datetime.time(5, 30), None))
711        rtn = IS_TIME()("5:30 pm")
712        self.assertEqual(rtn, (datetime.time(17, 30), None))
713        rtn = IS_TIME()("5:30 whatever")
714        self.assertEqual(
715            rtn, ("5:30 whatever", "Enter time as hh:mm:ss (seconds, am, pm optional)")
716        )
717        rtn = IS_TIME()("5:30 20")
718        self.assertEqual(
719            rtn, ("5:30 20", "Enter time as hh:mm:ss (seconds, am, pm optional)")
720        )
721        rtn = IS_TIME()("24:30")
722        self.assertEqual(
723            rtn, ("24:30", "Enter time as hh:mm:ss (seconds, am, pm optional)")
724        )
725        rtn = IS_TIME()("21:60")
726        self.assertEqual(
727            rtn, ("21:60", "Enter time as hh:mm:ss (seconds, am, pm optional)")
728        )
729        rtn = IS_TIME()("21:30::")
730        self.assertEqual(
731            rtn, ("21:30::", "Enter time as hh:mm:ss (seconds, am, pm optional)")
732        )
733        rtn = IS_TIME()("")
734        self.assertEqual(rtn, ("", "Enter time as hh:mm:ss (seconds, am, pm optional)"))
735
736    def test_IS_DATE(self):
737        v = IS_DATE(format="%m/%d/%Y", error_message="oops")
738        rtn = v("03/03/2008")
739        self.assertEqual(rtn, (datetime.date(2008, 3, 3), None))
740        rtn = v("31/03/2008")
741        self.assertEqual(rtn, ("31/03/2008", "oops"))
742        rtn = IS_DATE(format="%m/%d/%Y", error_message="oops").formatter(
743            datetime.date(1834, 12, 14)
744        )
745        self.assertEqual(rtn, "12/14/1834")
746
747    def test_IS_DATETIME(self):
748        v = IS_DATETIME(format="%m/%d/%Y %H:%M", error_message="oops")
749        rtn = v("03/03/2008 12:40")
750        self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 12, 40), None))
751        rtn = v("31/03/2008 29:40")
752        self.assertEqual(rtn, ("31/03/2008 29:40", "oops"))
753        # Test timezone is removed and value is properly converted
754        #
755        # https://github.com/web2py/web2py/issues/1094
756
757        class DummyTimezone(datetime.tzinfo):
758
759            ONE = datetime.timedelta(hours=1)
760
761            def utcoffset(self, dt):
762                return DummyTimezone.ONE
763
764            def tzname(self, dt):
765                return "UTC+1"
766
767            def dst(self, dt):
768                return DummyTimezone.ONE
769
770            def localize(self, dt, is_dst=False):
771                return dt.replace(tzinfo=self)
772
773        v = IS_DATETIME(
774            format="%Y-%m-%d %H:%M", error_message="oops", timezone=DummyTimezone()
775        )
776        rtn = v("1982-12-14 08:00")
777        self.assertEqual(rtn, (datetime.datetime(1982, 12, 14, 7, 0), None))
778
779    def test_IS_DATE_IN_RANGE(self):
780        v = IS_DATE_IN_RANGE(
781            minimum=datetime.date(2008, 1, 1),
782            maximum=datetime.date(2009, 12, 31),
783            format="%m/%d/%Y",
784            error_message="oops",
785        )
786
787        rtn = v("03/03/2008")
788        self.assertEqual(rtn, (datetime.date(2008, 3, 3), None))
789        rtn = v("03/03/2010")
790        self.assertEqual(rtn, ("03/03/2010", "oops"))
791        rtn = v(datetime.date(2008, 3, 3))
792        self.assertEqual(rtn, (datetime.date(2008, 3, 3), None))
793        rtn = v(datetime.date(2010, 3, 3))
794        self.assertEqual(rtn, (datetime.date(2010, 3, 3), "oops"))
795        v = IS_DATE_IN_RANGE(maximum=datetime.date(2009, 12, 31), format="%m/%d/%Y")
796        rtn = v("03/03/2010")
797        self.assertEqual(rtn, ("03/03/2010", "Enter date on or before 12/31/2009"))
798        v = IS_DATE_IN_RANGE(minimum=datetime.date(2008, 1, 1), format="%m/%d/%Y")
799        rtn = v("03/03/2007")
800        self.assertEqual(rtn, ("03/03/2007", "Enter date on or after 01/01/2008"))
801        v = IS_DATE_IN_RANGE(
802            minimum=datetime.date(2008, 1, 1),
803            maximum=datetime.date(2009, 12, 31),
804            format="%m/%d/%Y",
805        )
806        rtn = v("03/03/2007")
807        self.assertEqual(
808            rtn, ("03/03/2007", "Enter date in range 01/01/2008 12/31/2009")
809        )
810
811    def test_IS_DATETIME_IN_RANGE(self):
812        v = IS_DATETIME_IN_RANGE(
813            minimum=datetime.datetime(2008, 1, 1, 12, 20),
814            maximum=datetime.datetime(2009, 12, 31, 12, 20),
815            format="%m/%d/%Y %H:%M",
816            error_message="oops",
817        )
818        rtn = v("03/03/2008 12:40")
819        self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 12, 40), None))
820        rtn = v("03/03/2010 10:34")
821        self.assertEqual(rtn, ("03/03/2010 10:34", "oops"))
822        rtn = v(datetime.datetime(2008, 3, 3, 0, 0))
823        self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 0, 0), None))
824        rtn = v(datetime.datetime(2010, 3, 3, 0, 0))
825        self.assertEqual(rtn, (datetime.datetime(2010, 3, 3, 0, 0), "oops"))
826        v = IS_DATETIME_IN_RANGE(
827            maximum=datetime.datetime(2009, 12, 31, 12, 20), format="%m/%d/%Y %H:%M:%S"
828        )
829        rtn = v("03/03/2010 12:20:00")
830        self.assertEqual(
831            rtn,
832            (
833                "03/03/2010 12:20:00",
834                "Enter date and time on or before 12/31/2009 12:20:00",
835            ),
836        )
837        v = IS_DATETIME_IN_RANGE(
838            minimum=datetime.datetime(2008, 1, 1, 12, 20), format="%m/%d/%Y %H:%M:%S"
839        )
840        rtn = v("03/03/2007 12:20:00")
841        self.assertEqual(
842            rtn,
843            (
844                "03/03/2007 12:20:00",
845                "Enter date and time on or after 01/01/2008 12:20:00",
846            ),
847        )
848        v = IS_DATETIME_IN_RANGE(
849            minimum=datetime.datetime(2008, 1, 1, 12, 20),
850            maximum=datetime.datetime(2009, 12, 31, 12, 20),
851            format="%m/%d/%Y %H:%M:%S",
852        )
853        rtn = v("03/03/2007 12:20:00")
854        self.assertEqual(
855            rtn,
856            (
857                "03/03/2007 12:20:00",
858                "Enter date and time in range 01/01/2008 12:20:00 12/31/2009 12:20:00",
859            ),
860        )
861        v = IS_DATETIME_IN_RANGE(
862            maximum=datetime.datetime(2009, 12, 31, 12, 20),
863            format="%Y-%m-%d %H:%M:%S",
864            error_message="oops",
865        )
866        rtn = v("clearly not a date")
867        self.assertEqual(rtn, ("clearly not a date", "oops"))
868
869    def test_IS_LIST_OF(self):
870        values = [0, 1, 2, 3, 4]
871        rtn = IS_LIST_OF(IS_INT_IN_RANGE(0, 10))(values)
872        self.assertEqual(rtn, (values, None))
873        values.append(11)
874        rtn = IS_LIST_OF(IS_INT_IN_RANGE(0, 10))(values)
875        self.assertEqual(rtn, (values, "Enter an integer between 0 and 9"))
876        rtn = IS_LIST_OF(IS_INT_IN_RANGE(0, 10))(1)
877        self.assertEqual(rtn, ([1], None))
878        rtn = IS_LIST_OF(IS_INT_IN_RANGE(0, 10), minimum=10)([1, 2])
879        self.assertEqual(rtn, ([1, 2], "Minimum length is 10"))
880        rtn = IS_LIST_OF(IS_INT_IN_RANGE(0, 10), maximum=2)([1, 2, 3])
881        self.assertEqual(rtn, ([1, 2, 3], "Maximum length is 2"))
882        # regression test for issue 742
883        rtn = IS_LIST_OF(minimum=1)("")
884        self.assertEqual(rtn, ("", "Minimum length is 1"))
885
886    def test_IS_LOWER(self):
887        rtn = IS_LOWER()("ABC")
888        self.assertEqual(rtn, ("abc", None))
889        rtn = IS_LOWER()(b"ABC")
890        self.assertEqual(rtn, (b"abc", None))
891        rtn = IS_LOWER()("Ñ")
892        self.assertEqual(rtn, ("ñ", None))
893
894    def test_IS_UPPER(self):
895        rtn = IS_UPPER()("abc")
896        self.assertEqual(rtn, ("ABC", None))
897        rtn = IS_UPPER()(b"abc")
898        self.assertEqual(rtn, (b"ABC", None))
899        rtn = IS_UPPER()("ñ")
900        self.assertEqual(rtn, ("Ñ", None))
901
902    def test_IS_SLUG(self):
903        rtn = IS_SLUG()("abc123")
904        self.assertEqual(rtn, ("abc123", None))
905        rtn = IS_SLUG()("ABC123")
906        self.assertEqual(rtn, ("abc123", None))
907        rtn = IS_SLUG()("abc-123")
908        self.assertEqual(rtn, ("abc-123", None))
909        rtn = IS_SLUG()("abc--123")
910        self.assertEqual(rtn, ("abc-123", None))
911        rtn = IS_SLUG()("abc 123")
912        self.assertEqual(rtn, ("abc-123", None))
913        rtn = IS_SLUG()("abc\t_123")
914        self.assertEqual(rtn, ("abc-123", None))
915        rtn = IS_SLUG()("-abc-")
916        self.assertEqual(rtn, ("abc", None))
917        rtn = IS_SLUG()("--a--b--_ -c--")
918        self.assertEqual(rtn, ("a-b-c", None))
919        rtn = IS_SLUG()("abc&amp;123")
920        self.assertEqual(rtn, ("abc123", None))
921        rtn = IS_SLUG()("abc&amp;123&amp;def")
922        self.assertEqual(rtn, ("abc123def", None))
923        rtn = IS_SLUG()("ñ")
924        self.assertEqual(rtn, ("n", None))
925        rtn = IS_SLUG(maxlen=4)("abc123")
926        self.assertEqual(rtn, ("abc1", None))
927        rtn = IS_SLUG()("abc_123")
928        self.assertEqual(rtn, ("abc-123", None))
929        rtn = IS_SLUG(keep_underscores=False)("abc_123")
930        self.assertEqual(rtn, ("abc-123", None))
931        rtn = IS_SLUG(keep_underscores=True)("abc_123")
932        self.assertEqual(rtn, ("abc_123", None))
933        rtn = IS_SLUG(check=False)("abc")
934        self.assertEqual(rtn, ("abc", None))
935        rtn = IS_SLUG(check=True)("abc")
936        self.assertEqual(rtn, ("abc", None))
937        rtn = IS_SLUG(check=False)("a bc")
938        self.assertEqual(rtn, ("a-bc", None))
939        rtn = IS_SLUG(check=True)("a bc")
940        self.assertEqual(rtn, ("a bc", "Must be slug"))
941
942    def test_ANY_OF(self):
943        rtn = ANY_OF([IS_EMAIL(), IS_ALPHANUMERIC()])("a@b.co")
944        self.assertEqual(rtn, ("a@b.co", None))
945        rtn = ANY_OF([IS_EMAIL(), IS_ALPHANUMERIC()])("abco")
946        self.assertEqual(rtn, ("abco", None))
947        rtn = ANY_OF([IS_EMAIL(), IS_ALPHANUMERIC()])("@ab.co")
948        self.assertEqual(rtn, ("@ab.co", "Enter only letters, numbers, and underscore"))
949        rtn = ANY_OF([IS_ALPHANUMERIC(), IS_EMAIL()])("@ab.co")
950        self.assertEqual(rtn, ("@ab.co", "Enter a valid email address"))
951        rtn = ANY_OF([IS_DATE(), IS_EMAIL()])("a@b.co")
952        self.assertEqual(rtn, ("a@b.co", None))
953        rtn = ANY_OF([IS_DATE(), IS_EMAIL()])("1982-12-14")
954        self.assertEqual(rtn, (datetime.date(1982, 12, 14), None))
955        rtn = ANY_OF([IS_DATE(format="%m/%d/%Y"), IS_EMAIL()]).formatter(
956            datetime.date(1834, 12, 14)
957        )
958        self.assertEqual(rtn, "12/14/1834")
959
960    class CustomValidator(Validator):
961        """ Custom Validator not overloading .validate() """
962
963        def __call__(self, value):
964            return (value, None) if value else (value, "invalid!")
965
966    @staticmethod
967    def custom_validator_func(value):
968        """ Validation function instead of Validator subclass """
969        return (value, None) if value else (value, "invalid!")
970
971    def test_IS_EMPTY_OR(self):
972        rtn = IS_EMPTY_OR(IS_EMAIL())("abc@def.com")
973        self.assertEqual(rtn, ("abc@def.com", None))
974        rtn = IS_EMPTY_OR(IS_EMAIL())("   ")
975        self.assertEqual(rtn, (None, None))
976        rtn = IS_EMPTY_OR(IS_EMAIL(), null="abc")("   ")
977        self.assertEqual(rtn, ("abc", None))
978        rtn = IS_EMPTY_OR(IS_EMAIL(), null="abc", empty_regex="def")("def")
979        self.assertEqual(rtn, ("abc", None))
980        rtn = IS_EMPTY_OR(IS_EMAIL())("abc")
981        self.assertEqual(rtn, ("abc", "Enter a valid email address"))
982        rtn = IS_EMPTY_OR(IS_EMAIL())(" abc ")
983        self.assertEqual(rtn, (" abc ", "Enter a valid email address"))
984        rtn = IS_EMPTY_OR(
985            IS_IN_SET([("id1", "first label"), ("id2", "second label")], zero="zero")
986        ).options(zero=False)
987        self.assertEqual(
988            rtn, [("", ""), ("id1", "first label"), ("id2", "second label")]
989        )
990        rtn = IS_EMPTY_OR(
991            IS_IN_SET([("id1", "first label"), ("id2", "second label")], zero="zero")
992        ).options()
993        self.assertEqual(
994            rtn, [("", "zero"), ("id1", "first label"), ("id2", "second label")]
995        )
996        rtn = IS_EMPTY_OR((IS_LOWER(), IS_EMAIL()))("AAA")
997        self.assertEqual(rtn, ("AAA", "Enter a valid email address"))
998        rtn = IS_EMPTY_OR([IS_LOWER(), IS_EMAIL()])("AAA")
999        self.assertEqual(rtn, ("AAA", "Enter a valid email address"))
1000        rtn = IS_EMPTY_OR(self.CustomValidator())(1)
1001        self.assertEqual(rtn, (1, None))
1002        rtn = IS_EMPTY_OR(self.CustomValidator())(0)
1003        self.assertEqual(rtn, (0, "invalid!"))
1004        rtn = IS_EMPTY_OR(self.custom_validator_func)(1)
1005        self.assertEqual(rtn, (1, None))
1006        rtn = IS_EMPTY_OR(self.custom_validator_func)(0)
1007        self.assertEqual(rtn, (0, "invalid!"))
1008
1009    def test_CLEANUP(self):
1010        rtn = CLEANUP()("helloò")
1011        self.assertEqual(rtn, ("hello", None))
1012
1013    def test_CRYPT(self):
1014        rtn = str(CRYPT(digest_alg="md5", salt=True)("test")[0])
1015        self.myassertRegex(rtn, r"^md5\$.{16}\$.{32}$")
1016        rtn = str(CRYPT(digest_alg="sha1", salt=True)("test")[0])
1017        self.myassertRegex(rtn, r"^sha1\$.{16}\$.{40}$")
1018        rtn = str(CRYPT(digest_alg="sha256", salt=True)("test")[0])
1019        self.myassertRegex(rtn, r"^sha256\$.{16}\$.{64}$")
1020        rtn = str(CRYPT(digest_alg="sha384", salt=True)("test")[0])
1021        self.myassertRegex(rtn, r"^sha384\$.{16}\$.{96}$")
1022        rtn = str(CRYPT(digest_alg="sha512", salt=True)("test")[0])
1023        self.myassertRegex(rtn, r"^sha512\$.{16}\$.{128}$")
1024        alg = "pbkdf2(1000,20,sha512)"
1025        rtn = str(CRYPT(digest_alg=alg, salt=True)("test")[0])
1026        self.myassertRegex(rtn, r"^pbkdf2\(1000,20,sha512\)\$.{16}\$.{40}$")
1027        rtn = str(CRYPT(digest_alg="md5", key="mykey", salt=True)("test")[0])
1028        self.myassertRegex(rtn, r"^md5\$.{16}\$.{32}$")
1029        a = str(CRYPT(digest_alg="sha1", salt=False)("test")[0])
1030        self.assertEqual(CRYPT(digest_alg="sha1", salt=False)("test")[0], a)
1031        self.assertEqual(CRYPT(digest_alg="sha1", salt=False)("test")[0], a[6:])
1032        self.assertEqual(CRYPT(digest_alg="md5", salt=False)("test")[0], a)
1033        self.assertEqual(CRYPT(digest_alg="md5", salt=False)("test")[0], a[6:])
1034
1035    def test_IS_STRONG(self):
1036        rtn = IS_STRONG(es=True)("Abcd1234")
1037        self.assertEqual(
1038            rtn,
1039            (
1040                "Abcd1234",
1041                "Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|",
1042            ),
1043        )
1044        rtn = IS_STRONG(es=True)("Abcd1234!")
1045        self.assertEqual(rtn, ("Abcd1234!", None))
1046        rtn = IS_STRONG(es=True, entropy=1)("a")
1047        self.assertEqual(rtn, ("a", None))
1048        rtn = IS_STRONG(es=True, entropy=1, min=2)("a")
1049        self.assertEqual(rtn, ("a", "Minimum length is 2"))
1050        rtn = IS_STRONG(es=True, entropy=100)("abc123")
1051        self.assertEqual(rtn, ("abc123", "Password too simple (32.35/100)"))
1052        rtn = IS_STRONG(es=True, entropy=100)("and")
1053        self.assertEqual(rtn, ("and", "Password too simple (14.57/100)"))
1054        rtn = IS_STRONG(es=True, entropy=100)("aaa")
1055        self.assertEqual(rtn, ("aaa", "Password too simple (14.42/100)"))
1056        rtn = IS_STRONG(es=True, entropy=100)("a1d")
1057        self.assertEqual(rtn, ("a1d", "Password too simple (15.97/100)"))
1058        rtn = IS_STRONG(es=True, entropy=100)("añd")
1059        if PY2:
1060            self.assertEqual(rtn, ("a\xc3\xb1d", "Password too simple (32.66/100)"))
1061        else:
1062            self.assertEqual(rtn, ("añd", "Password too simple (31.26/100)"))
1063        rtn = IS_STRONG()("********")
1064        self.assertEqual(rtn, ("********", None))
1065        rtn = IS_STRONG(es=True, max=4)("abcde")
1066        self.assertEqual(
1067            rtn,
1068            (
1069                "abcde",
1070                "|".join(
1071                    [
1072                        "Minimum length is 8",
1073                        "Maximum length is 4",
1074                        "Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|",
1075                        "Must include at least 1 uppercase",
1076                        "Must include at least 1 number",
1077                    ]
1078                ),
1079            ),
1080        )
1081        rtn = IS_STRONG(es=True)("abcde")
1082        self.assertEqual(
1083            rtn,
1084            (
1085                "abcde",
1086                "|".join(
1087                    [
1088                        "Minimum length is 8",
1089                        "Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|",
1090                        "Must include at least 1 uppercase",
1091                        "Must include at least 1 number",
1092                    ]
1093                ),
1094            ),
1095        )
1096        rtn = IS_STRONG(upper=0, lower=0, number=0, es=True)("Abcde1")
1097        self.assertEqual(
1098            rtn,
1099            (
1100                "Abcde1",
1101                "|".join(
1102                    [
1103                        "Minimum length is 8",
1104                        "Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|",
1105                        "May not include any uppercase letters",
1106                        "May not include any lowercase letters",
1107                        "May not include any numbers",
1108                    ]
1109                ),
1110            ),
1111        )
1112        rtn = IS_STRONG(special=0, es=True)("Abcde1!")
1113        self.assertEqual(
1114            rtn,
1115            (
1116                "Abcde1!",
1117                "|".join(
1118                    [
1119                        "Minimum length is 8",
1120                        "May not contain any of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|",
1121                    ]
1122                ),
1123            ),
1124        )
1125        rtn = IS_STRONG(upper=False, number=False, special=False, es=True)("Abcde1!")
1126        self.assertEqual(rtn, ("Abcde1!", "Minimum length is 8"))
1127
1128    def test_IS_IMAGE(self):
1129        class DummyImageFile(object):
1130            def __init__(self, filename, ext, width, height):
1131                from io import BytesIO
1132                import struct
1133
1134                self.filename = filename + "." + ext
1135                self.file = BytesIO()
1136                if ext == "bmp":
1137                    self.file.write(b"BM")
1138                    self.file.write(b" " * 16)
1139                    self.file.write(struct.pack("<LL", width, height))
1140                elif ext == "gif":
1141                    self.file.write(b"GIF87a")
1142                    self.file.write(struct.pack("<HHB", width, height, 0))
1143                elif ext in ("jpg", "jpeg"):
1144                    self.file.write(b"\xFF\xD8")
1145                    self.file.write(struct.pack("!BBH", 0xFF, 0xC0, 5))
1146                    self.file.write(struct.pack("!xHH", height, width))
1147                elif ext == "png":
1148                    self.file.write(b"\211PNG\r\n\032\n")
1149                    self.file.write(b" " * 4)
1150                    self.file.write(b"IHDR")
1151                    self.file.write(struct.pack("!LL", width, height))
1152                self.file.seek(0)
1153
1154        img = DummyImageFile("test", "bmp", 50, 100)
1155        rtn = IS_IMAGE()(img)
1156        self.assertEqual(rtn, (img, None))
1157        rtn = IS_IMAGE(error_message="oops", maxsize=(100, 50))(img)
1158        self.assertEqual(rtn, (img, "oops"))
1159        rtn = IS_IMAGE(error_message="oops", minsize=(100, 50))(img)
1160        self.assertEqual(rtn, (img, "oops"))
1161        rtn = IS_IMAGE(error_message="oops", aspectratio=(1, 1))(img)
1162        self.assertEqual(rtn, (img, "oops"))
1163
1164        img = DummyImageFile("test", "gif", 50, 100)
1165        rtn = IS_IMAGE()(img)
1166        self.assertEqual(rtn, (img, None))
1167        rtn = IS_IMAGE(error_message="oops", maxsize=(100, 50))(img)
1168        self.assertEqual(rtn, (img, "oops"))
1169        rtn = IS_IMAGE(error_message="oops", minsize=(100, 50))(img)
1170        self.assertEqual(rtn, (img, "oops"))
1171        rtn = IS_IMAGE(error_message="oops", aspectratio=(1, 1))(img)
1172        self.assertEqual(rtn, (img, "oops"))
1173
1174        img = DummyImageFile("test", "jpeg", 50, 100)
1175        rtn = IS_IMAGE()(img)
1176        self.assertEqual(rtn, (img, None))
1177        rtn = IS_IMAGE(error_message="oops", maxsize=(100, 50))(img)
1178        self.assertEqual(rtn, (img, "oops"))
1179        rtn = IS_IMAGE(error_message="oops", minsize=(100, 50))(img)
1180        self.assertEqual(rtn, (img, "oops"))
1181        rtn = IS_IMAGE(error_message="oops", aspectratio=(1, 1))(img)
1182        self.assertEqual(rtn, (img, "oops"))
1183
1184        img = DummyImageFile("test", "png", 50, 100)
1185        rtn = IS_IMAGE()(img)
1186        self.assertEqual(rtn, (img, None))
1187        rtn = IS_IMAGE(error_message="oops", maxsize=(100, 50))(img)
1188        self.assertEqual(rtn, (img, "oops"))
1189        rtn = IS_IMAGE(error_message="oops", minsize=(100, 50))(img)
1190        self.assertEqual(rtn, (img, "oops"))
1191        rtn = IS_IMAGE(error_message="oops", aspectratio=(1, 1))(img)
1192        self.assertEqual(rtn, (img, "oops"))
1193
1194        img = DummyImageFile("test", "xls", 50, 100)
1195        rtn = IS_IMAGE(error_message="oops")(img)
1196        self.assertEqual(rtn, (img, "oops"))
1197
1198    def test_IS_FILE(self):
1199        import cgi
1200        from io import BytesIO
1201
1202        def gen_fake(filename):
1203            formdata_file_data = (
1204                """
1205---123
1206Content-Disposition: form-data; name="key2"
1207
1208value2y
1209---123
1210Content-Disposition: form-data; name="file_attach"; filename="%s"
1211Content-Type: text/plain
1212
1213this is the content of the fake file
1214
1215---123--
1216"""
1217                % filename
1218            )
1219            formdata_file_environ = {
1220                "CONTENT_LENGTH": str(len(formdata_file_data)),
1221                "CONTENT_TYPE": "multipart/form-data; boundary=-123",
1222                "QUERY_STRING": "key1=value1&key2=value2x",
1223                "REQUEST_METHOD": "POST",
1224            }
1225            return cgi.FieldStorage(
1226                fp=BytesIO(to_bytes(formdata_file_data)), environ=formdata_file_environ
1227            )["file_attach"]
1228
1229        fake = gen_fake("example.pdf")
1230        rtn = IS_FILE(extension="pdf")(fake)
1231        self.assertEqual(rtn, (fake, None))
1232        fake = gen_fake("example.gif")
1233        rtn = IS_FILE(extension="pdf")(fake)
1234        self.assertEqual(rtn, (fake, "Enter valid filename"))
1235        fake = gen_fake("multiple.pdf")
1236        rtn = IS_FILE(extension=["pdf", "png"])(fake)
1237        self.assertEqual(rtn, (fake, None))
1238        fake = gen_fake("multiple.png")
1239        rtn = IS_FILE(extension=["pdf", "png"])(fake)
1240        self.assertEqual(rtn, (fake, None))
1241        fake = gen_fake("multiple.gif")
1242        rtn = IS_FILE(extension=["pdf", "png"])(fake)
1243        self.assertEqual(rtn, (fake, "Enter valid filename"))
1244        fake = gen_fake("backup2014.tar.gz")
1245        rtn = IS_FILE(
1246            filename=re.compile("backup.*"), extension="tar.gz", lastdot=False
1247        )(fake)
1248        self.assertEqual(rtn, (fake, None))
1249        fake = gen_fake("README")
1250        rtn = IS_FILE(filename="README", extension="", case=0)(fake)
1251        self.assertEqual(rtn, (fake, None))
1252        fake = gen_fake("readme")
1253        rtn = IS_FILE(filename="README", extension="", case=0)(fake)
1254        self.assertEqual(rtn, (fake, "Enter valid filename"))
1255        fake = gen_fake("readme")
1256        rtn = IS_FILE(filename="README", case=2)(fake)
1257        self.assertEqual(rtn, (fake, None))
1258        fake = gen_fake("README")
1259        rtn = IS_FILE(filename="README", case=2)(fake)
1260        self.assertEqual(rtn, (fake, None))
1261        rtn = IS_FILE(extension="pdf")("example.pdf")
1262        self.assertEqual(rtn, ("example.pdf", "Enter valid filename"))
1263
1264    def test_IS_UPLOAD_FILENAME(self):
1265        import cgi
1266        from io import BytesIO
1267
1268        def gen_fake(filename):
1269            formdata_file_data = (
1270                """
1271---123
1272Content-Disposition: form-data; name="key2"
1273
1274value2y
1275---123
1276Content-Disposition: form-data; name="file_attach"; filename="%s"
1277Content-Type: text/plain
1278
1279this is the content of the fake file
1280
1281---123--
1282"""
1283                % filename
1284            )
1285            formdata_file_environ = {
1286                "CONTENT_LENGTH": str(len(formdata_file_data)),
1287                "CONTENT_TYPE": "multipart/form-data; boundary=-123",
1288                "QUERY_STRING": "key1=value1&key2=value2x",
1289                "REQUEST_METHOD": "POST",
1290            }
1291            return cgi.FieldStorage(
1292                fp=BytesIO(to_bytes(formdata_file_data)), environ=formdata_file_environ
1293            )["file_attach"]
1294
1295        fake = gen_fake("example.pdf")
1296        rtn = IS_UPLOAD_FILENAME(extension="pdf")(fake)
1297        self.assertEqual(rtn, (fake, None))
1298        fake = gen_fake("example.gif")
1299        rtn = IS_UPLOAD_FILENAME(extension="pdf")(fake)
1300        self.assertEqual(rtn, (fake, "Enter valid filename"))
1301        fake = gen_fake("backup2014.tar.gz")
1302        rtn = IS_UPLOAD_FILENAME(
1303            filename="backup.*", extension="tar.gz", lastdot=False
1304        )(fake)
1305        self.assertEqual(rtn, (fake, None))
1306        fake = gen_fake("README")
1307        rtn = IS_UPLOAD_FILENAME(filename="^README$", extension="^$", case=0)(fake)
1308        self.assertEqual(rtn, (fake, None))
1309        fake = gen_fake("readme")
1310        rtn = IS_UPLOAD_FILENAME(filename="^README$", extension="^$", case=0)(fake)
1311        self.assertEqual(rtn, (fake, "Enter valid filename"))
1312        fake = gen_fake("readme")
1313        rtn = IS_UPLOAD_FILENAME(filename="README", case=2)(fake)
1314        self.assertEqual(rtn, (fake, None))
1315        fake = gen_fake("README")
1316        rtn = IS_UPLOAD_FILENAME(filename="README", case=2)(fake)
1317        self.assertEqual(rtn, (fake, None))
1318        rtn = IS_UPLOAD_FILENAME(extension="pdf")("example.pdf")
1319        self.assertEqual(rtn, ("example.pdf", "Enter valid filename"))
1320
1321    def test_IS_IPV4(self):
1322        rtn = IS_IPV4()("1.2.3.4")
1323        self.assertEqual(rtn, ("1.2.3.4", None))
1324        rtn = IS_IPV4()("255.255.255.255")
1325        self.assertEqual(rtn, ("255.255.255.255", None))
1326        rtn = IS_IPV4()("1.2.3.4 ")
1327        self.assertEqual(rtn, ("1.2.3.4 ", "Enter valid IPv4 address"))
1328        rtn = IS_IPV4()("1.2.3.4.5")
1329        self.assertEqual(rtn, ("1.2.3.4.5", "Enter valid IPv4 address"))
1330        rtn = IS_IPV4()("123.123")
1331        self.assertEqual(rtn, ("123.123", "Enter valid IPv4 address"))
1332        rtn = IS_IPV4()("1111.2.3.4")
1333        self.assertEqual(rtn, ("1111.2.3.4", "Enter valid IPv4 address"))
1334        rtn = IS_IPV4()("0111.2.3.4")
1335        self.assertEqual(rtn, ("0111.2.3.4", "Enter valid IPv4 address"))
1336        rtn = IS_IPV4()("256.2.3.4")
1337        self.assertEqual(rtn, ("256.2.3.4", "Enter valid IPv4 address"))
1338        rtn = IS_IPV4()("300.2.3.4")
1339        self.assertEqual(rtn, ("300.2.3.4", "Enter valid IPv4 address"))
1340        rtn = IS_IPV4(minip="1.2.3.4", maxip="1.2.3.4")("1.2.3.4")
1341        self.assertEqual(rtn, ("1.2.3.4", None))
1342        rtn = IS_IPV4(minip="1.2.3.5", maxip="1.2.3.9", error_message="bad ip")(
1343            "1.2.3.4"
1344        )
1345        self.assertEqual(rtn, ("1.2.3.4", "bad ip"))
1346        rtn = IS_IPV4(maxip="1.2.3.4", invert=True)("127.0.0.1")
1347        self.assertEqual(rtn, ("127.0.0.1", None))
1348        rtn = IS_IPV4(maxip="1.2.3.4", invert=True)("1.2.3.4")
1349        self.assertEqual(rtn, ("1.2.3.4", "Enter valid IPv4 address"))
1350        rtn = IS_IPV4(is_localhost=True)("127.0.0.1")
1351        self.assertEqual(rtn, ("127.0.0.1", None))
1352        rtn = IS_IPV4(is_localhost=True)("1.2.3.4")
1353        self.assertEqual(rtn, ("1.2.3.4", "Enter valid IPv4 address"))
1354        rtn = IS_IPV4(is_localhost=False)("127.0.0.1")
1355        self.assertEqual(rtn, ("127.0.0.1", "Enter valid IPv4 address"))
1356        rtn = IS_IPV4(maxip="100.0.0.0", is_localhost=True)("127.0.0.1")
1357        self.assertEqual(rtn, ("127.0.0.1", "Enter valid IPv4 address"))
1358
1359    def test_IS_IPV6(self):
1360        rtn = IS_IPV6()("fe80::126c:8ffa:fe22:b3af")
1361        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af", None))
1362        rtn = IS_IPV6()("192.168.1.1")
1363        self.assertEqual(rtn, ("192.168.1.1", "Enter valid IPv6 address"))
1364        rtn = IS_IPV6(error_message="bad ip")("192.168.1.1")
1365        self.assertEqual(rtn, ("192.168.1.1", "bad ip"))
1366        rtn = IS_IPV6(is_link_local=True)("fe80::126c:8ffa:fe22:b3af")
1367        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af", None))
1368        rtn = IS_IPV6(is_link_local=False)("fe80::126c:8ffa:fe22:b3af")
1369        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af", "Enter valid IPv6 address"))
1370        rtn = IS_IPV6(is_link_local=True)("2001::126c:8ffa:fe22:b3af")
1371        self.assertEqual(rtn, ("2001::126c:8ffa:fe22:b3af", "Enter valid IPv6 address"))
1372        rtn = IS_IPV6(is_multicast=True)("2001::126c:8ffa:fe22:b3af")
1373        self.assertEqual(rtn, ("2001::126c:8ffa:fe22:b3af", "Enter valid IPv6 address"))
1374        rtn = IS_IPV6(is_multicast=True)("ff00::126c:8ffa:fe22:b3af")
1375        self.assertEqual(rtn, ("ff00::126c:8ffa:fe22:b3af", None))
1376        # with py3.ipaddress '2001::126c:8ffa:fe22:b3af' is considered private
1377        # with py2.ipaddress '2001::126c:8ffa:fe22:b3af' is considered private
1378        # with gluon.contrib.ipaddr(both current and trunk) is not considered private
1379        rtn = IS_IPV6(is_routeable=False)("2001::126c:8ffa:fe22:b3af")
1380        self.assertEqual(rtn, ("2001::126c:8ffa:fe22:b3af", None))
1381        rtn = IS_IPV6(is_routeable=True)("ff00::126c:8ffa:fe22:b3af")
1382        self.assertEqual(rtn, ("ff00::126c:8ffa:fe22:b3af", "Enter valid IPv6 address"))
1383        rtn = IS_IPV6(subnets="2001::/32")("2001::8ffa:fe22:b3af")
1384        self.assertEqual(rtn, ("2001::8ffa:fe22:b3af", None))
1385        rtn = IS_IPV6(subnets="fb00::/8")("2001::8ffa:fe22:b3af")
1386        self.assertEqual(rtn, ("2001::8ffa:fe22:b3af", "Enter valid IPv6 address"))
1387        rtn = IS_IPV6(subnets=["fc00::/8", "2001::/32"])("2001::8ffa:fe22:b3af")
1388        self.assertEqual(rtn, ("2001::8ffa:fe22:b3af", None))
1389        rtn = IS_IPV6(subnets="invalidsubnet")("2001::8ffa:fe22:b3af")
1390        self.assertEqual(rtn, ("2001::8ffa:fe22:b3af", "invalid subnet provided"))
1391
1392    def test_IS_IPADDRESS(self):
1393        rtn = IS_IPADDRESS()("192.168.1.5")
1394        self.assertEqual(rtn, ("192.168.1.5", None))
1395        rtn = IS_IPADDRESS(is_ipv6=False)("192.168.1.5")
1396        self.assertEqual(rtn, ("192.168.1.5", None))
1397        rtn = IS_IPADDRESS()("255.255.255.255")
1398        self.assertEqual(rtn, ("255.255.255.255", None))
1399        rtn = IS_IPADDRESS()("192.168.1.5 ")
1400        self.assertEqual(rtn, ("192.168.1.5 ", "Enter valid IP address"))
1401        rtn = IS_IPADDRESS()("192.168.1.1.5")
1402        self.assertEqual(rtn, ("192.168.1.1.5", "Enter valid IP address"))
1403        rtn = IS_IPADDRESS()("123.123")
1404        self.assertEqual(rtn, ("123.123", "Enter valid IP address"))
1405        rtn = IS_IPADDRESS()("1111.2.3.4")
1406        self.assertEqual(rtn, ("1111.2.3.4", "Enter valid IP address"))
1407        rtn = IS_IPADDRESS()("0111.2.3.4")
1408        self.assertEqual(rtn, ("0111.2.3.4", "Enter valid IP address"))
1409        rtn = IS_IPADDRESS()("256.2.3.4")
1410        self.assertEqual(rtn, ("256.2.3.4", "Enter valid IP address"))
1411        rtn = IS_IPADDRESS()("300.2.3.4")
1412        self.assertEqual(rtn, ("300.2.3.4", "Enter valid IP address"))
1413        rtn = IS_IPADDRESS(minip="192.168.1.0", maxip="192.168.1.255")("192.168.1.100")
1414        self.assertEqual(rtn, ("192.168.1.100", None))
1415        rtn = IS_IPADDRESS(minip="1.2.3.5", maxip="1.2.3.9", error_message="bad ip")(
1416            "1.2.3.4"
1417        )
1418        self.assertEqual(rtn, ("1.2.3.4", "bad ip"))
1419        rtn = IS_IPADDRESS(maxip="1.2.3.4", invert=True)("127.0.0.1")
1420        self.assertEqual(rtn, ("127.0.0.1", None))
1421        rtn = IS_IPADDRESS(maxip="192.168.1.4", invert=True)("192.168.1.4")
1422        self.assertEqual(rtn, ("192.168.1.4", "Enter valid IP address"))
1423        rtn = IS_IPADDRESS(is_localhost=True)("127.0.0.1")
1424        self.assertEqual(rtn, ("127.0.0.1", None))
1425        rtn = IS_IPADDRESS(is_localhost=True)("192.168.1.10")
1426        self.assertEqual(rtn, ("192.168.1.10", "Enter valid IP address"))
1427        rtn = IS_IPADDRESS(is_localhost=False)("127.0.0.1")
1428        self.assertEqual(rtn, ("127.0.0.1", "Enter valid IP address"))
1429        rtn = IS_IPADDRESS(maxip="100.0.0.0", is_localhost=True)("127.0.0.1")
1430        self.assertEqual(rtn, ("127.0.0.1", "Enter valid IP address"))
1431        rtn = IS_IPADDRESS()("aaa")
1432        self.assertEqual(rtn, ("aaa", "Enter valid IP address"))
1433
1434        rtn = IS_IPADDRESS()("fe80::126c:8ffa:fe22:b3af")
1435        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af", None))
1436        rtn = IS_IPADDRESS(is_ipv4=False)("fe80::126c:8ffa:fe22:b3af")
1437        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af", None))
1438        rtn = IS_IPADDRESS()("fe80::126c:8ffa:fe22:b3af  ")
1439        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af  ", "Enter valid IP address"))
1440        rtn = IS_IPADDRESS(is_ipv4=True)("fe80::126c:8ffa:fe22:b3af")
1441        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af", "Enter valid IP address"))
1442        rtn = IS_IPADDRESS(is_ipv6=True)("192.168.1.1")
1443        self.assertEqual(rtn, ("192.168.1.1", "Enter valid IP address"))
1444        rtn = IS_IPADDRESS(is_ipv6=True, error_message="bad ip")("192.168.1.1")
1445        self.assertEqual(rtn, ("192.168.1.1", "bad ip"))
1446        rtn = IS_IPADDRESS(is_link_local=True)("fe80::126c:8ffa:fe22:b3af")
1447        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af", None))
1448        rtn = IS_IPADDRESS(is_link_local=False)("fe80::126c:8ffa:fe22:b3af")
1449        self.assertEqual(rtn, ("fe80::126c:8ffa:fe22:b3af", "Enter valid IP address"))
1450        rtn = IS_IPADDRESS(is_link_local=True)("2001::126c:8ffa:fe22:b3af")
1451        self.assertEqual(rtn, ("2001::126c:8ffa:fe22:b3af", "Enter valid IP address"))
1452        rtn = IS_IPADDRESS(is_multicast=True)("2001::126c:8ffa:fe22:b3af")
1453        self.assertEqual(rtn, ("2001::126c:8ffa:fe22:b3af", "Enter valid IP address"))
1454        rtn = IS_IPADDRESS(is_multicast=True)("ff00::126c:8ffa:fe22:b3af")
1455        self.assertEqual(rtn, ("ff00::126c:8ffa:fe22:b3af", None))
1456        rtn = IS_IPADDRESS(is_routeable=True)("ff00::126c:8ffa:fe22:b3af")
1457        self.assertEqual(rtn, ("ff00::126c:8ffa:fe22:b3af", "Enter valid IP address"))
1458        rtn = IS_IPADDRESS(subnets="2001::/32")("2001::8ffa:fe22:b3af")
1459        self.assertEqual(rtn, ("2001::8ffa:fe22:b3af", None))
1460        rtn = IS_IPADDRESS(subnets="fb00::/8")("2001::8ffa:fe22:b3af")
1461        self.assertEqual(rtn, ("2001::8ffa:fe22:b3af", "Enter valid IP address"))
1462        rtn = IS_IPADDRESS(subnets=["fc00::/8", "2001::/32"])("2001::8ffa:fe22:b3af")
1463        self.assertEqual(rtn, ("2001::8ffa:fe22:b3af", None))
1464        rtn = IS_IPADDRESS(subnets="invalidsubnet")("2001::8ffa:fe22:b3af")
1465        self.assertEqual(rtn, ("2001::8ffa:fe22:b3af", "invalid subnet provided"))
Note: See TracBrowser for help on using the repository browser.