From 1d04f8837eb13687382db4ccbe3ef98c2c2eee66 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 14 Mar 2016 12:16:52 -0500 Subject: [PATCH] resorted tests as suggested by BuhtigithuB --- gluon/tests/test_validators.py | 1053 ++++++++++++++++---------------- 1 file changed, 535 insertions(+), 518 deletions(-) diff --git a/gluon/tests/test_validators.py b/gluon/tests/test_validators.py index c5adc87f..64255a7b 100644 --- a/gluon/tests/test_validators.py +++ b/gluon/tests/test_validators.py @@ -31,8 +31,7 @@ class TestValidators(unittest.TestCase): self.assertEqual(utc.dst(dt), UTC.ZERO) self.assertEqual(utc.tzname(dt), 'UTC') - - #port from python 2.7, needed for 2.5 and 2.6 tests + # port from python 2.7, needed for 2.5 and 2.6 tests def assertRegexpMatches(self, text, expected_regexp, msg=None): """Fail the test unless the text matches the regular expression.""" if isinstance(expected_regexp, basestring): @@ -43,146 +42,203 @@ class TestValidators(unittest.TestCase): msg, expected_regexp.pattern, text) raise self.failureException(msg) - def test_ANY_OF(self): - rtn = ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('a@b.co') - self.assertEqual(rtn, ('a@b.co', None)) - rtn = ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('abco') - self.assertEqual(rtn, ('abco', None)) - rtn = ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('@ab.co') - self.assertEqual(rtn, ('@ab.co', 'Enter only letters, numbers, and underscore')) - rtn = ANY_OF([IS_ALPHANUMERIC(),IS_EMAIL()])('@ab.co') - self.assertEqual(rtn, ('@ab.co', 'Enter a valid email address')) - rtn = ANY_OF([IS_DATE(),IS_EMAIL()])('a@b.co') - self.assertEqual(rtn, ('a@b.co', None)) - rtn = ANY_OF([IS_DATE(),IS_EMAIL()])('1982-12-14') - self.assertEqual(rtn, (datetime.date(1982, 12, 14), None)) - - def test_CLEANUP(self): - rtn = CLEANUP()('helloò') + def test_IS_MATCH(self): + rtn = IS_MATCH('.+')('hello') self.assertEqual(rtn, ('hello', None)) + rtn = IS_MATCH('hell')('hello') + self.assertEqual(rtn, ('hello', None)) + rtn = IS_MATCH('hell.*', strict=False)('hello') + self.assertEqual(rtn, ('hello', None)) + rtn = IS_MATCH('hello')('shello') + self.assertEqual(rtn, ('shello', 'Invalid expression')) + rtn = IS_MATCH('hello', search=True)('shello') + self.assertEqual(rtn, ('shello', None)) + rtn = IS_MATCH('hello', search=True, strict=False)('shellox') + self.assertEqual(rtn, ('shellox', None)) + rtn = IS_MATCH('.*hello.*', search=True, strict=False)('shellox') + self.assertEqual(rtn, ('shellox', None)) + rtn = IS_MATCH('.+')('') + self.assertEqual(rtn, ('', 'Invalid expression')) + rtn = IS_MATCH('hell', strict=True)('hellas') + self.assertEqual(rtn, ('hellas', 'Invalid expression')) + rtn = IS_MATCH('hell$', strict=True)('hellas') + self.assertEqual(rtn, ('hellas', 'Invalid expression')) + rtn = IS_MATCH('^.hell$', strict=True)('shell') + self.assertEqual(rtn, ('shell', None)) + rtn = IS_MATCH(u'hell', is_unicode=True)('àòè') + self.assertEqual(rtn, ('\xc3\xa0\xc3\xb2\xc3\xa8', 'Invalid expression')) + rtn = IS_MATCH(u'hell', is_unicode=True)(u'hell') + self.assertEqual(rtn, (u'hell', None)) + rtn = IS_MATCH('hell', is_unicode=True)(u'hell') + self.assertEqual(rtn, (u'hell', None)) + # regr test for #1044 + rtn = IS_MATCH('hello')(u'\xff') + self.assertEqual(rtn, (u'\xff', 'Invalid expression')) - def test_CRYPT(self): + def test_IS_EQUAL_TO(self): + rtn = IS_EQUAL_TO('aaa')('aaa') + self.assertEqual(rtn, ('aaa', None)) + rtn = IS_EQUAL_TO('aaa')('aab') + self.assertEqual(rtn, ('aab', 'No match')) - rtn = str(CRYPT(digest_alg='md5',salt=True)('test')[0]) - self.assertRegexpMatches(rtn, r'^md5\$.{16}\$.{32}$') - rtn = str(CRYPT(digest_alg='sha1',salt=True)('test')[0]) - self.assertRegexpMatches(rtn, r'^sha1\$.{16}\$.{40}$') - rtn = str(CRYPT(digest_alg='sha256',salt=True)('test')[0]) - self.assertRegexpMatches(rtn, r'^sha256\$.{16}\$.{64}$') - rtn = str(CRYPT(digest_alg='sha384',salt=True)('test')[0]) - self.assertRegexpMatches(rtn, r'^sha384\$.{16}\$.{96}$') - rtn = str(CRYPT(digest_alg='sha512',salt=True)('test')[0]) - self.assertRegexpMatches(rtn, r'^sha512\$.{16}\$.{128}$') - alg = 'pbkdf2(1000,20,sha512)' - rtn = str(CRYPT(digest_alg=alg,salt=True)('test')[0]) - self.assertRegexpMatches(rtn, r'^pbkdf2\(1000,20,sha512\)\$.{16}\$.{40}$') - rtn = str(CRYPT(digest_alg='md5',key='mykey',salt=True)('test')[0]) - self.assertRegexpMatches(rtn, r'^md5\$.{16}\$.{32}$') - a = str(CRYPT(digest_alg='sha1',salt=False)('test')[0]) - self.assertEqual(CRYPT(digest_alg='sha1',salt=False)('test')[0], a) - self.assertEqual(CRYPT(digest_alg='sha1',salt=False)('test')[0], a[6:]) - self.assertEqual(CRYPT(digest_alg='md5',salt=False)('test')[0], a) - self.assertEqual(CRYPT(digest_alg='md5',salt=False)('test')[0], a[6:]) - - def test_IS_ALPHANUMERIC(self): - rtn = IS_ALPHANUMERIC()('1') + def test_IS_EXPR(self): + rtn = IS_EXPR('int(value) < 2')('1') self.assertEqual(rtn, ('1', None)) - rtn = IS_ALPHANUMERIC()('') + rtn = IS_EXPR('int(value) < 2')('2') + self.assertEqual(rtn, ('2', 'Invalid expression')) + rtn = IS_EXPR(lambda value: int(value))('1') + self.assertEqual(rtn, ('1', 1)) + rtn = IS_EXPR(lambda value: int(value) < 2 and 'invalid' or None)('2') + self.assertEqual(rtn, ('2', None)) + + def test_IS_LENGTH(self): + rtn = IS_LENGTH()('') self.assertEqual(rtn, ('', None)) - rtn = IS_ALPHANUMERIC()('A_a') - self.assertEqual(rtn, ('A_a', None)) - rtn = IS_ALPHANUMERIC()('!') - self.assertEqual(rtn, ('!', 'Enter only letters, numbers, and underscore')) + rtn = IS_LENGTH()('1234567890') + self.assertEqual(rtn, ('1234567890', None)) + rtn = IS_LENGTH(maxsize=5, minsize=0)('1234567890') # too long + self.assertEqual(rtn, ('1234567890', 'Enter from 0 to 5 characters')) + rtn = IS_LENGTH(maxsize=50, minsize=20)('1234567890') # too short + self.assertEqual(rtn, ('1234567890', 'Enter from 20 to 50 characters')) + rtn = IS_LENGTH()(None) + self.assertEqual(rtn, (None, None)) + rtn = IS_LENGTH(minsize=0)(None) + self.assertEqual(rtn, (None, None)) + rtn = IS_LENGTH(minsize=1)(None) + self.assertEqual(rtn, (None, 'Enter from 1 to 255 characters')) + rtn = IS_LENGTH(minsize=1)([]) + self.assertEqual(rtn, ([], 'Enter from 1 to 255 characters')) + rtn = IS_LENGTH(minsize=1)([1, 2]) + self.assertEqual(rtn, ([1, 2], None)) + rtn = IS_LENGTH(minsize=1)([1]) + self.assertEqual(rtn, ([1], None)) + # test non utf-8 str + cpstr = u'lálá'.encode('cp1252') + rtn = IS_LENGTH(minsize=4)(cpstr) + self.assertEqual(rtn, (cpstr, None)) + rtn = IS_LENGTH(maxsize=4)(cpstr) + self.assertEqual(rtn, (cpstr, None)) + rtn = IS_LENGTH(minsize=0, maxsize=3)(cpstr) + self.assertEqual(rtn, (cpstr, 'Enter from 0 to 3 characters')) + # test unicode + rtn = IS_LENGTH(2)(u'°2') + self.assertEqual(rtn, ('\xc2\xb02', None)) + rtn = IS_LENGTH(2)(u'°12') + self.assertEqual(rtn, (u'\xb012', 'Enter from 0 to 2 characters')) + # test automatic str() + rtn = IS_LENGTH(minsize=1)(1) + self.assertEqual(rtn, ('1', None)) + rtn = IS_LENGTH(minsize=2)(1) + self.assertEqual(rtn, (1, 'Enter from 2 to 255 characters')) + # test FieldStorage + import cgi + from StringIO import StringIO + a = cgi.FieldStorage() + a.file = StringIO('abc') + rtn = IS_LENGTH(minsize=4)(a) + self.assertEqual(rtn, (a, 'Enter from 4 to 255 characters')) + urlencode_data = "key2=value2x&key3=value3&key4=value4" + urlencode_environ = { + 'CONTENT_LENGTH': str(len(urlencode_data)), + 'CONTENT_TYPE': 'application/x-www-form-urlencoded', + 'QUERY_STRING': 'key1=value1&key2=value2y', + 'REQUEST_METHOD': 'POST', + } + fake_stdin = StringIO(urlencode_data) + fake_stdin.seek(0) + a = cgi.FieldStorage(fp=fake_stdin, environ=urlencode_environ) + rtn = IS_LENGTH(minsize=6)(a) + self.assertEqual(rtn, (a, 'Enter from 6 to 255 characters')) + a = cgi.FieldStorage() + rtn = IS_LENGTH(minsize=6)(a) + self.assertEqual(rtn, (a, 'Enter from 6 to 255 characters')) + rtn = IS_LENGTH(6)(a) + self.assertEqual(rtn, (a, None)) - def test_IS_DATE_IN_RANGE(self): - v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1), - maximum=datetime.date(2009,12,31), - format="%m/%d/%Y",error_message="oops") + def test_IS_JSON(self): + rtn = IS_JSON()('{"a": 100}') + self.assertEqual(rtn, ({u'a': 100}, None)) + rtn = IS_JSON()('spam1234') + self.assertEqual(rtn, ('spam1234', 'Invalid json')) - rtn = v('03/03/2008') - self.assertEqual(rtn, (datetime.date(2008, 3, 3), None)) - rtn = v('03/03/2010') - self.assertEqual(rtn, ('03/03/2010', 'oops')) - rtn = v(datetime.date(2008,3,3)) - self.assertEqual(rtn, (datetime.date(2008, 3, 3), None)) - rtn = v(datetime.date(2010,3,3)) - self.assertEqual(rtn, (datetime.date(2010, 3, 3), 'oops')) - v = IS_DATE_IN_RANGE(maximum=datetime.date(2009,12,31), - format="%m/%d/%Y") - rtn = v('03/03/2010') - self.assertEqual(rtn, ('03/03/2010', 'Enter date on or before 12/31/2009')) - v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1), - format="%m/%d/%Y") - rtn = v('03/03/2007') - self.assertEqual(rtn, ('03/03/2007', 'Enter date on or after 01/01/2008')) - v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1), - maximum=datetime.date(2009,12,31), - format="%m/%d/%Y") - rtn = v('03/03/2007') - self.assertEqual(rtn, ('03/03/2007', 'Enter date in range 01/01/2008 12/31/2009')) + def test_IS_IN_SET(self): + rtn = IS_IN_SET(['max', 'john'])('max') + self.assertEqual(rtn, ('max', None)) + rtn = IS_IN_SET(['max', 'john'])('massimo') + self.assertEqual(rtn, ('massimo', 'Value not allowed')) + rtn = IS_IN_SET(['max', 'john'], multiple=True)(('max', 'john')) + self.assertEqual(rtn, (('max', 'john'), None)) + rtn = IS_IN_SET(['max', 'john'], multiple=True)(('bill', 'john')) + self.assertEqual(rtn, (('bill', 'john'), 'Value not allowed')) + rtn = IS_IN_SET(('id1','id2'), ['first label','second label'])('id1') # Traditional way + self.assertEqual(rtn, ('id1', None)) + rtn = IS_IN_SET({'id1':'first label', 'id2':'second label'})('id1') + self.assertEqual(rtn, ('id1', None)) + import itertools + rtn = IS_IN_SET(itertools.chain(['1','3','5'],['2','4','6']))('1') + self.assertEqual(rtn, ('1', None)) + rtn = IS_IN_SET([('id1','first label'), ('id2','second label')])('id1') # Redundant way + self.assertEqual(rtn, ('id1', None)) - def test_IS_DATE(self): - v = IS_DATE(format="%m/%d/%Y",error_message="oops") - rtn = v('03/03/2008') - self.assertEqual(rtn, (datetime.date(2008, 3, 3), None)) - rtn = v('31/03/2008') - self.assertEqual(rtn, ('31/03/2008', 'oops')) + # TODO: def test_IS_IN_DB(self): - def test_IS_DATETIME_IN_RANGE(self): - v = IS_DATETIME_IN_RANGE( - minimum=datetime.datetime(2008,1,1,12,20), - maximum=datetime.datetime(2009,12,31,12,20), - format="%m/%d/%Y %H:%M",error_message="oops") - rtn = v('03/03/2008 12:40') - self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 12, 40), None)) - rtn = v('03/03/2010 10:34') - self.assertEqual(rtn, ('03/03/2010 10:34', 'oops')) - rtn = v(datetime.datetime(2008,3,3,0,0)) - self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 0, 0), None)) - rtn = v(datetime.datetime(2010,3,3,0,0)) - self.assertEqual(rtn, (datetime.datetime(2010, 3, 3, 0, 0), 'oops')) - v = IS_DATETIME_IN_RANGE(maximum=datetime.datetime(2009,12,31,12,20), - format='%m/%d/%Y %H:%M:%S') - rtn = v('03/03/2010 12:20:00') - self.assertEqual(rtn, ('03/03/2010 12:20:00', 'Enter date and time on or before 12/31/2009 12:20:00')) - v = IS_DATETIME_IN_RANGE(minimum=datetime.datetime(2008,1,1,12,20), - format='%m/%d/%Y %H:%M:%S') - rtn = v('03/03/2007 12:20:00') - self.assertEqual(rtn, ('03/03/2007 12:20:00', 'Enter date and time on or after 01/01/2008 12:20:00')) - v = IS_DATETIME_IN_RANGE(minimum=datetime.datetime(2008,1,1,12,20), - maximum=datetime.datetime(2009,12,31,12,20), - format='%m/%d/%Y %H:%M:%S') - rtn = v('03/03/2007 12:20:00') - self.assertEqual(rtn, ('03/03/2007 12:20:00', 'Enter date and time in range 01/01/2008 12:20:00 12/31/2009 12:20:00')) - v = IS_DATETIME_IN_RANGE(maximum=datetime.datetime(2009,12,31,12,20), - format='%Y-%m-%d %H:%M:%S', error_message='oops') - rtn = v('clearly not a date') - self.assertEqual(rtn, ('clearly not a date', 'oops')) + # TODO: def test_IS_NOT_IN_DB(self): - def test_IS_DATETIME(self): - v = IS_DATETIME(format="%m/%d/%Y %H:%M",error_message="oops") - rtn = v('03/03/2008 12:40') - self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 12, 40), None)) - rtn = v('31/03/2008 29:40') - self.assertEqual(rtn, ('31/03/2008 29:40', 'oops')) - # Test timezone is removed and value is properly converted - # - # https://github.com/web2py/web2py/issues/1094 - class DummyTimezone(datetime.tzinfo): + def test_IS_INT_IN_RANGE(self): + rtn = IS_INT_IN_RANGE(1,5)('4') + self.assertEqual(rtn, (4, None)) + rtn = IS_INT_IN_RANGE(1,5)(4) + self.assertEqual(rtn, (4, None)) + rtn = IS_INT_IN_RANGE(1,5)(1) + self.assertEqual(rtn, (1, None)) + rtn = IS_INT_IN_RANGE(1,5)(5) + self.assertEqual(rtn, (5, 'Enter an integer between 1 and 4')) + rtn = IS_INT_IN_RANGE(1,5)(5) + self.assertEqual(rtn, (5, 'Enter an integer between 1 and 4')) + rtn = IS_INT_IN_RANGE(1,5)(3.5) + self.assertEqual(rtn, (3.5, 'Enter an integer between 1 and 4')) + rtn = IS_INT_IN_RANGE(None,5)('4') + self.assertEqual(rtn, (4, None)) + rtn = IS_INT_IN_RANGE(None,5)('6') + self.assertEqual(rtn, ('6', 'Enter an integer less than or equal to 4')) + rtn = IS_INT_IN_RANGE(1,None)('4') + self.assertEqual(rtn, (4, None)) + rtn = IS_INT_IN_RANGE(1,None)('0') + self.assertEqual(rtn, ('0', 'Enter an integer greater than or equal to 1')) + rtn = IS_INT_IN_RANGE()(6) + self.assertEqual(rtn, (6, None)) + rtn = IS_INT_IN_RANGE()('abc') + self.assertEqual(rtn, ('abc', 'Enter an integer')) - ONE = datetime.timedelta(hours=1) - - def utcoffset(self, dt): - return DummyTimezone.ONE - def tzname(self, dt): - return "UTC+1" - def dst(self, dt): - return DummyTimezone.ONE - def localize(self, dt, is_dst=False): - return dt.replace(tzinfo=self) - v = IS_DATETIME(format="%Y-%m-%d %H:%M", error_message="oops", timezone=DummyTimezone()) - rtn = v('1982-12-14 08:00') - self.assertEqual(rtn, (datetime.datetime(1982, 12, 14, 7, 0), None)) + def test_IS_FLOAT_IN_RANGE(self): + rtn = IS_FLOAT_IN_RANGE(1,5)('4') + self.assertEqual(rtn, (4.0, None)) + rtn = IS_FLOAT_IN_RANGE(1,5)(4) + self.assertEqual(rtn, (4.0, None)) + rtn = IS_FLOAT_IN_RANGE(1,5)(1) + self.assertEqual(rtn, (1.0, None)) + rtn = IS_FLOAT_IN_RANGE(1,5)(5.25) + self.assertEqual(rtn, (5.25, 'Enter a number between 1 and 5')) + rtn = IS_FLOAT_IN_RANGE(1,5)(6.0) + self.assertEqual(rtn, (6.0, 'Enter a number between 1 and 5')) + rtn = IS_FLOAT_IN_RANGE(1,5)(3.5) + self.assertEqual(rtn, (3.5, None)) + rtn = IS_FLOAT_IN_RANGE(1,None)(3.5) + self.assertEqual(rtn, (3.5, None)) + rtn = IS_FLOAT_IN_RANGE(None,5)(3.5) + self.assertEqual(rtn, (3.5, None)) + rtn = IS_FLOAT_IN_RANGE(1,None)(0.5) + self.assertEqual(rtn, (0.5, 'Enter a number greater than or equal to 1')) + rtn = IS_FLOAT_IN_RANGE(None,5)(6.5) + self.assertEqual(rtn, (6.5, 'Enter a number less than or equal to 5')) + rtn = IS_FLOAT_IN_RANGE()(6.5) + self.assertEqual(rtn, (6.5, None)) + rtn = IS_FLOAT_IN_RANGE()('abc') + self.assertEqual(rtn, ('abc', 'Enter a number')) + rtn = IS_FLOAT_IN_RANGE()('6,5') + self.assertEqual(rtn, ('6,5', 'Enter a number')) + rtn = IS_FLOAT_IN_RANGE(dot=',')('6.5') + self.assertEqual(rtn, (6.5, None)) def test_IS_DECIMAL_IN_RANGE(self): rtn = IS_DECIMAL_IN_RANGE(1,5)('4') @@ -230,6 +286,42 @@ class TestValidators(unittest.TestCase): rtn = IS_DECIMAL_IN_RANGE(1,5)(decimal.Decimal('4')) self.assertEqual(rtn, (decimal.Decimal('4'), None)) + def test_IS_NOT_EMPTY(self): + rtn = IS_NOT_EMPTY()(1) + self.assertEqual(rtn, (1, None)) + rtn = IS_NOT_EMPTY()(0) + self.assertEqual(rtn, (0, None)) + rtn = IS_NOT_EMPTY()('x') + self.assertEqual(rtn, ('x', None)) + rtn = IS_NOT_EMPTY()(' x ') + self.assertEqual(rtn, ('x', None)) + rtn = IS_NOT_EMPTY()(None) + self.assertEqual(rtn, (None, 'Enter a value')) + rtn = IS_NOT_EMPTY()('') + self.assertEqual(rtn, ('', 'Enter a value')) + rtn = IS_NOT_EMPTY()(' ') + self.assertEqual(rtn, ('', 'Enter a value')) + rtn = IS_NOT_EMPTY()(' \n\t') + self.assertEqual(rtn, ('', 'Enter a value')) + rtn = IS_NOT_EMPTY()([]) + self.assertEqual(rtn, ([], 'Enter a value')) + rtn = IS_NOT_EMPTY(empty_regex='def')('def') + self.assertEqual(rtn, ('', 'Enter a value')) + rtn = IS_NOT_EMPTY(empty_regex='de[fg]')('deg') + self.assertEqual(rtn, ('', 'Enter a value')) + rtn = IS_NOT_EMPTY(empty_regex='def')('abc') + self.assertEqual(rtn, ('abc', None)) + + def test_IS_ALPHANUMERIC(self): + rtn = IS_ALPHANUMERIC()('1') + self.assertEqual(rtn, ('1', None)) + rtn = IS_ALPHANUMERIC()('') + self.assertEqual(rtn, ('', None)) + rtn = IS_ALPHANUMERIC()('A_a') + self.assertEqual(rtn, ('A_a', None)) + rtn = IS_ALPHANUMERIC()('!') + self.assertEqual(rtn, ('!', 'Enter only letters, numbers, and underscore')) + def test_IS_EMAIL(self): rtn = IS_EMAIL()('a@b.com') self.assertEqual(rtn, ('a@b.com', None)) @@ -308,6 +400,130 @@ class TestValidators(unittest.TestCase): rtn = IS_LIST_OF_EMAILS()(';'.join(emails)) self.assertEqual(rtn, ('localguy@localhost;_Yosemite.Sam@example.com;a', 'Invalid emails: a')) + # TODO: def test_IS_GENERIC_URL(self): + + # TODO: def test_IS_HTTP_URL(self): + + # TODO: def test_IS_URL(self): + + def test_IS_TIME(self): + rtn = IS_TIME()('21:30') + self.assertEqual(rtn, (datetime.time(21, 30), None)) + rtn = IS_TIME()('21-30') + self.assertEqual(rtn, (datetime.time(21, 30), None)) + rtn = IS_TIME()('21.30') + self.assertEqual(rtn, (datetime.time(21, 30), None)) + rtn = IS_TIME()('21:30:59') + self.assertEqual(rtn, (datetime.time(21, 30, 59), None)) + rtn = IS_TIME()('5:30') + self.assertEqual(rtn, (datetime.time(5, 30), None)) + rtn = IS_TIME()('5:30 am') + self.assertEqual(rtn, (datetime.time(5, 30), None)) + rtn = IS_TIME()('5:30 pm') + self.assertEqual(rtn, (datetime.time(17, 30), None)) + rtn = IS_TIME()('5:30 whatever') + self.assertEqual(rtn, ('5:30 whatever', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) + rtn = IS_TIME()('5:30 20') + self.assertEqual(rtn, ('5:30 20', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) + rtn = IS_TIME()('24:30') + self.assertEqual(rtn, ('24:30', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) + rtn = IS_TIME()('21:60') + self.assertEqual(rtn, ('21:60', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) + rtn = IS_TIME()('21:30::') + self.assertEqual(rtn, ('21:30::', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) + rtn = IS_TIME()('') + self.assertEqual(rtn, ('', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) + + def test_IS_DATE(self): + v = IS_DATE(format="%m/%d/%Y",error_message="oops") + rtn = v('03/03/2008') + self.assertEqual(rtn, (datetime.date(2008, 3, 3), None)) + rtn = v('31/03/2008') + self.assertEqual(rtn, ('31/03/2008', 'oops')) + + def test_IS_DATETIME(self): + v = IS_DATETIME(format="%m/%d/%Y %H:%M",error_message="oops") + rtn = v('03/03/2008 12:40') + self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 12, 40), None)) + rtn = v('31/03/2008 29:40') + self.assertEqual(rtn, ('31/03/2008 29:40', 'oops')) + # Test timezone is removed and value is properly converted + # + # https://github.com/web2py/web2py/issues/1094 + class DummyTimezone(datetime.tzinfo): + + ONE = datetime.timedelta(hours=1) + + def utcoffset(self, dt): + return DummyTimezone.ONE + def tzname(self, dt): + return "UTC+1" + def dst(self, dt): + return DummyTimezone.ONE + def localize(self, dt, is_dst=False): + return dt.replace(tzinfo=self) + v = IS_DATETIME(format="%Y-%m-%d %H:%M", error_message="oops", timezone=DummyTimezone()) + rtn = v('1982-12-14 08:00') + self.assertEqual(rtn, (datetime.datetime(1982, 12, 14, 7, 0), None)) + + def test_IS_DATE_IN_RANGE(self): + v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1), + maximum=datetime.date(2009,12,31), + format="%m/%d/%Y",error_message="oops") + + rtn = v('03/03/2008') + self.assertEqual(rtn, (datetime.date(2008, 3, 3), None)) + rtn = v('03/03/2010') + self.assertEqual(rtn, ('03/03/2010', 'oops')) + rtn = v(datetime.date(2008,3,3)) + self.assertEqual(rtn, (datetime.date(2008, 3, 3), None)) + rtn = v(datetime.date(2010,3,3)) + self.assertEqual(rtn, (datetime.date(2010, 3, 3), 'oops')) + v = IS_DATE_IN_RANGE(maximum=datetime.date(2009,12,31), + format="%m/%d/%Y") + rtn = v('03/03/2010') + self.assertEqual(rtn, ('03/03/2010', 'Enter date on or before 12/31/2009')) + v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1), + format="%m/%d/%Y") + rtn = v('03/03/2007') + self.assertEqual(rtn, ('03/03/2007', 'Enter date on or after 01/01/2008')) + v = IS_DATE_IN_RANGE(minimum=datetime.date(2008,1,1), + maximum=datetime.date(2009,12,31), + format="%m/%d/%Y") + rtn = v('03/03/2007') + self.assertEqual(rtn, ('03/03/2007', 'Enter date in range 01/01/2008 12/31/2009')) + + def test_IS_DATETIME_IN_RANGE(self): + v = IS_DATETIME_IN_RANGE( + minimum=datetime.datetime(2008,1,1,12,20), + maximum=datetime.datetime(2009,12,31,12,20), + format="%m/%d/%Y %H:%M",error_message="oops") + rtn = v('03/03/2008 12:40') + self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 12, 40), None)) + rtn = v('03/03/2010 10:34') + self.assertEqual(rtn, ('03/03/2010 10:34', 'oops')) + rtn = v(datetime.datetime(2008,3,3,0,0)) + self.assertEqual(rtn, (datetime.datetime(2008, 3, 3, 0, 0), None)) + rtn = v(datetime.datetime(2010,3,3,0,0)) + self.assertEqual(rtn, (datetime.datetime(2010, 3, 3, 0, 0), 'oops')) + v = IS_DATETIME_IN_RANGE(maximum=datetime.datetime(2009,12,31,12,20), + format='%m/%d/%Y %H:%M:%S') + rtn = v('03/03/2010 12:20:00') + self.assertEqual(rtn, ('03/03/2010 12:20:00', 'Enter date and time on or before 12/31/2009 12:20:00')) + v = IS_DATETIME_IN_RANGE(minimum=datetime.datetime(2008,1,1,12,20), + format='%m/%d/%Y %H:%M:%S') + rtn = v('03/03/2007 12:20:00') + self.assertEqual(rtn, ('03/03/2007 12:20:00', 'Enter date and time on or after 01/01/2008 12:20:00')) + v = IS_DATETIME_IN_RANGE(minimum=datetime.datetime(2008,1,1,12,20), + maximum=datetime.datetime(2009,12,31,12,20), + format='%m/%d/%Y %H:%M:%S') + rtn = v('03/03/2007 12:20:00') + self.assertEqual(rtn, ('03/03/2007 12:20:00', 'Enter date and time in range 01/01/2008 12:20:00 12/31/2009 12:20:00')) + v = IS_DATETIME_IN_RANGE(maximum=datetime.datetime(2009,12,31,12,20), + format='%Y-%m-%d %H:%M:%S', error_message='oops') + rtn = v('clearly not a date') + self.assertEqual(rtn, ('clearly not a date', 'oops')) + def test_IS_LIST_OF(self): values = [0,1,2,3,4] rtn = IS_LIST_OF(IS_INT_IN_RANGE(0, 10))(values) @@ -325,6 +541,71 @@ class TestValidators(unittest.TestCase): rtn = IS_LIST_OF(minimum=1)('') self.assertEqual(rtn, ([], 'Enter between 1 and 100 values')) + def test_IS_LOWER(self): + rtn = IS_LOWER()('ABC') + self.assertEqual(rtn, ('abc', None)) + rtn = IS_LOWER()('Ñ') + self.assertEqual(rtn, ('\xc3\xb1', None)) + + def test_IS_UPPER(self): + rtn = IS_UPPER()('abc') + self.assertEqual(rtn, ('ABC', None)) + rtn = IS_UPPER()('ñ') + self.assertEqual(rtn, ('\xc3\x91', None)) + + def test_IS_SLUG(self): + rtn = IS_SLUG()('abc123') + self.assertEqual(rtn, ('abc123', None)) + rtn = IS_SLUG()('ABC123') + self.assertEqual(rtn, ('abc123', None)) + rtn = IS_SLUG()('abc-123') + self.assertEqual(rtn, ('abc-123', None)) + rtn = IS_SLUG()('abc--123') + self.assertEqual(rtn, ('abc-123', None)) + rtn = IS_SLUG()('abc 123') + self.assertEqual(rtn, ('abc-123', None)) + rtn = IS_SLUG()('abc\t_123') + self.assertEqual(rtn, ('abc-123', None)) + rtn = IS_SLUG()('-abc-') + self.assertEqual(rtn, ('abc', None)) + rtn = IS_SLUG()('--a--b--_ -c--') + self.assertEqual(rtn, ('a-b-c', None)) + rtn = IS_SLUG()('abc&123') + self.assertEqual(rtn, ('abc123', None)) + rtn = IS_SLUG()('abc&123&def') + self.assertEqual(rtn, ('abc123def', None)) + rtn = IS_SLUG()('ñ') + self.assertEqual(rtn, ('n', None)) + rtn = IS_SLUG(maxlen=4)('abc123') + self.assertEqual(rtn, ('abc1', None)) + rtn = IS_SLUG()('abc_123') + self.assertEqual(rtn, ('abc-123', None)) + rtn = IS_SLUG(keep_underscores=False)('abc_123') + self.assertEqual(rtn, ('abc-123', None)) + rtn = IS_SLUG(keep_underscores=True)('abc_123') + self.assertEqual(rtn, ('abc_123', None)) + rtn = IS_SLUG(check=False)('abc') + self.assertEqual(rtn, ('abc', None)) + rtn = IS_SLUG(check=True)('abc') + self.assertEqual(rtn, ('abc', None)) + rtn = IS_SLUG(check=False)('a bc') + self.assertEqual(rtn, ('a-bc', None)) + rtn = IS_SLUG(check=True)('a bc') + self.assertEqual(rtn, ('a bc', 'Must be slug')) + + def test_ANY_OF(self): + rtn = ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('a@b.co') + self.assertEqual(rtn, ('a@b.co', None)) + rtn = ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('abco') + self.assertEqual(rtn, ('abco', None)) + rtn = ANY_OF([IS_EMAIL(),IS_ALPHANUMERIC()])('@ab.co') + self.assertEqual(rtn, ('@ab.co', 'Enter only letters, numbers, and underscore')) + rtn = ANY_OF([IS_ALPHANUMERIC(),IS_EMAIL()])('@ab.co') + self.assertEqual(rtn, ('@ab.co', 'Enter a valid email address')) + rtn = ANY_OF([IS_DATE(),IS_EMAIL()])('a@b.co') + self.assertEqual(rtn, ('a@b.co', None)) + rtn = ANY_OF([IS_DATE(),IS_EMAIL()])('1982-12-14') + self.assertEqual(rtn, (datetime.date(1982, 12, 14), None)) def test_IS_EMPTY_OR(self): rtn = IS_EMPTY_OR(IS_EMAIL())('abc@def.com') @@ -340,91 +621,133 @@ class TestValidators(unittest.TestCase): rtn = IS_EMPTY_OR(IS_EMAIL())(' abc ') self.assertEqual(rtn, ('abc', 'Enter a valid email address')) - def test_IS_EXPR(self): - rtn = IS_EXPR('int(value) < 2')('1') - self.assertEqual(rtn, ('1', None)) - rtn = IS_EXPR('int(value) < 2')('2') - self.assertEqual(rtn, ('2', 'Invalid expression')) - rtn = IS_EXPR(lambda value: int(value))('1') - self.assertEqual(rtn, ('1', 1)) - rtn = IS_EXPR(lambda value: int(value) < 2 and 'invalid' or None)('2') - self.assertEqual(rtn, ('2', None)) + def test_CLEANUP(self): + rtn = CLEANUP()('helloò') + self.assertEqual(rtn, ('hello', None)) - def test_IS_FLOAT_IN_RANGE(self): - rtn = IS_FLOAT_IN_RANGE(1,5)('4') - self.assertEqual(rtn, (4.0, None)) - rtn = IS_FLOAT_IN_RANGE(1,5)(4) - self.assertEqual(rtn, (4.0, None)) - rtn = IS_FLOAT_IN_RANGE(1,5)(1) - self.assertEqual(rtn, (1.0, None)) - rtn = IS_FLOAT_IN_RANGE(1,5)(5.25) - self.assertEqual(rtn, (5.25, 'Enter a number between 1 and 5')) - rtn = IS_FLOAT_IN_RANGE(1,5)(6.0) - self.assertEqual(rtn, (6.0, 'Enter a number between 1 and 5')) - rtn = IS_FLOAT_IN_RANGE(1,5)(3.5) - self.assertEqual(rtn, (3.5, None)) - rtn = IS_FLOAT_IN_RANGE(1,None)(3.5) - self.assertEqual(rtn, (3.5, None)) - rtn = IS_FLOAT_IN_RANGE(None,5)(3.5) - self.assertEqual(rtn, (3.5, None)) - rtn = IS_FLOAT_IN_RANGE(1,None)(0.5) - self.assertEqual(rtn, (0.5, 'Enter a number greater than or equal to 1')) - rtn = IS_FLOAT_IN_RANGE(None,5)(6.5) - self.assertEqual(rtn, (6.5, 'Enter a number less than or equal to 5')) - rtn = IS_FLOAT_IN_RANGE()(6.5) - self.assertEqual(rtn, (6.5, None)) - rtn = IS_FLOAT_IN_RANGE()('abc') - self.assertEqual(rtn, ('abc', 'Enter a number')) - rtn = IS_FLOAT_IN_RANGE()('6,5') - self.assertEqual(rtn, ('6,5', 'Enter a number')) - rtn = IS_FLOAT_IN_RANGE(dot=',')('6.5') - self.assertEqual(rtn, (6.5, None)) + def test_CRYPT(self): + rtn = str(CRYPT(digest_alg='md5',salt=True)('test')[0]) + self.assertRegexpMatches(rtn, r'^md5\$.{16}\$.{32}$') + rtn = str(CRYPT(digest_alg='sha1',salt=True)('test')[0]) + self.assertRegexpMatches(rtn, r'^sha1\$.{16}\$.{40}$') + rtn = str(CRYPT(digest_alg='sha256',salt=True)('test')[0]) + self.assertRegexpMatches(rtn, r'^sha256\$.{16}\$.{64}$') + rtn = str(CRYPT(digest_alg='sha384',salt=True)('test')[0]) + self.assertRegexpMatches(rtn, r'^sha384\$.{16}\$.{96}$') + rtn = str(CRYPT(digest_alg='sha512',salt=True)('test')[0]) + self.assertRegexpMatches(rtn, r'^sha512\$.{16}\$.{128}$') + alg = 'pbkdf2(1000,20,sha512)' + rtn = str(CRYPT(digest_alg=alg,salt=True)('test')[0]) + self.assertRegexpMatches(rtn, r'^pbkdf2\(1000,20,sha512\)\$.{16}\$.{40}$') + rtn = str(CRYPT(digest_alg='md5',key='mykey',salt=True)('test')[0]) + self.assertRegexpMatches(rtn, r'^md5\$.{16}\$.{32}$') + a = str(CRYPT(digest_alg='sha1',salt=False)('test')[0]) + self.assertEqual(CRYPT(digest_alg='sha1',salt=False)('test')[0], a) + self.assertEqual(CRYPT(digest_alg='sha1',salt=False)('test')[0], a[6:]) + self.assertEqual(CRYPT(digest_alg='md5',salt=False)('test')[0], a) + self.assertEqual(CRYPT(digest_alg='md5',salt=False)('test')[0], a[6:]) + def test_IS_STRONG(self): + rtn = IS_STRONG(es=True)('Abcd1234') + self.assertEqual(rtn, ('Abcd1234', + 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|')) + rtn = IS_STRONG(es=True)('Abcd1234!') + self.assertEqual(rtn, ('Abcd1234!', None)) + rtn = IS_STRONG(es=True, entropy=1)('a') + self.assertEqual(rtn, ('a', None)) + rtn = IS_STRONG(es=True, entropy=1, min=2)('a') + self.assertEqual(rtn, ('a', 'Minimum length is 2')) + rtn = IS_STRONG(es=True, entropy=100)('abc123') + self.assertEqual(rtn, ('abc123', 'Entropy (32.35) less than required (100)')) + rtn = IS_STRONG(es=True, entropy=100)('and') + self.assertEqual(rtn, ('and', 'Entropy (14.57) less than required (100)')) + rtn = IS_STRONG(es=True, entropy=100)('aaa') + self.assertEqual(rtn, ('aaa', 'Entropy (14.42) less than required (100)')) + rtn = IS_STRONG(es=True, entropy=100)('a1d') + self.assertEqual(rtn, ('a1d', 'Entropy (15.97) less than required (100)')) + rtn = IS_STRONG(es=True, entropy=100)('añd') + self.assertEqual(rtn, ('a\xc3\xb1d', 'Entropy (18.13) less than required (100)')) + rtn = IS_STRONG()('********') + self.assertEqual(rtn, ('********', None)) + rtn = IS_STRONG(es=True, max=4)('abcde') + self.assertEqual(rtn, + ('abcde', + '|'.join(['Minimum length is 8', + 'Maximum length is 4', + 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|', + 'Must include at least 1 upper case', + 'Must include at least 1 number'])) + ) + rtn = IS_STRONG(es=True)('abcde') + self.assertEqual(rtn, + ('abcde', + '|'.join(['Minimum length is 8', + 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|', + 'Must include at least 1 upper case', + 'Must include at least 1 number'])) + ) + rtn = IS_STRONG(upper=0, lower=0, number=0, es=True)('Abcde1') + self.assertEqual(rtn, + ('Abcde1', + '|'.join(['Minimum length is 8', + 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|', + 'May not include any upper case letters', + 'May not include any lower case letters', + 'May not include any numbers'])) + ) - def test_IS_IN_SET(self): - rtn = IS_IN_SET(['max', 'john'])('max') - self.assertEqual(rtn, ('max', None)) - rtn = IS_IN_SET(['max', 'john'])('massimo') - self.assertEqual(rtn, ('massimo', 'Value not allowed')) - rtn = IS_IN_SET(['max', 'john'], multiple=True)(('max', 'john')) - self.assertEqual(rtn, (('max', 'john'), None)) - rtn = IS_IN_SET(['max', 'john'], multiple=True)(('bill', 'john')) - self.assertEqual(rtn, (('bill', 'john'), 'Value not allowed')) - rtn = IS_IN_SET(('id1','id2'), ['first label','second label'])('id1') # Traditional way - self.assertEqual(rtn, ('id1', None)) - rtn = IS_IN_SET({'id1':'first label', 'id2':'second label'})('id1') - self.assertEqual(rtn, ('id1', None)) - import itertools - rtn = IS_IN_SET(itertools.chain(['1','3','5'],['2','4','6']))('1') - self.assertEqual(rtn, ('1', None)) - rtn = IS_IN_SET([('id1','first label'), ('id2','second label')])('id1') # Redundant way - self.assertEqual(rtn, ('id1', None)) + # TODO: def test_IS_IN_SUBSET(self): - def test_IS_INT_IN_RANGE(self): - rtn = IS_INT_IN_RANGE(1,5)('4') - self.assertEqual(rtn, (4, None)) - rtn = IS_INT_IN_RANGE(1,5)(4) - self.assertEqual(rtn, (4, None)) - rtn = IS_INT_IN_RANGE(1,5)(1) - self.assertEqual(rtn, (1, None)) - rtn = IS_INT_IN_RANGE(1,5)(5) - self.assertEqual(rtn, (5, 'Enter an integer between 1 and 4')) - rtn = IS_INT_IN_RANGE(1,5)(5) - self.assertEqual(rtn, (5, 'Enter an integer between 1 and 4')) - rtn = IS_INT_IN_RANGE(1,5)(3.5) - self.assertEqual(rtn, (3.5, 'Enter an integer between 1 and 4')) - rtn = IS_INT_IN_RANGE(None,5)('4') - self.assertEqual(rtn, (4, None)) - rtn = IS_INT_IN_RANGE(None,5)('6') - self.assertEqual(rtn, ('6', 'Enter an integer less than or equal to 4')) - rtn = IS_INT_IN_RANGE(1,None)('4') - self.assertEqual(rtn, (4, None)) - rtn = IS_INT_IN_RANGE(1,None)('0') - self.assertEqual(rtn, ('0', 'Enter an integer greater than or equal to 1')) - rtn = IS_INT_IN_RANGE()(6) - self.assertEqual(rtn, (6, None)) - rtn = IS_INT_IN_RANGE()('abc') - self.assertEqual(rtn, ('abc', 'Enter an integer')) + # TODO: def test_IS_IMAGE(self): + + def test_IS_UPLOAD_FILENAME(self): + import cgi + from StringIO import StringIO + def gen_fake(filename): + formdata_file_data = """ +---123 +Content-Disposition: form-data; name="key2" + +value2y +---123 +Content-Disposition: form-data; name="file_attach"; filename="%s" +Content-Type: text/plain + +this is the content of the fake file + +---123-- +""" % filename + formdata_file_environ = { + 'CONTENT_LENGTH': str(len(formdata_file_data)), + 'CONTENT_TYPE': 'multipart/form-data; boundary=-123', + 'QUERY_STRING': 'key1=value1&key2=value2x', + 'REQUEST_METHOD': 'POST', + } + return cgi.FieldStorage(fp=StringIO(formdata_file_data), environ=formdata_file_environ)['file_attach'] + + fake = gen_fake('example.pdf') + rtn = IS_UPLOAD_FILENAME(extension='pdf')(fake) + self.assertEqual(rtn, (fake, None)) + fake = gen_fake('example.gif') + rtn = IS_UPLOAD_FILENAME(extension='pdf')(fake) + self.assertEqual(rtn, (fake, 'Enter valid filename')) + fake = gen_fake('backup2014.tar.gz') + rtn = IS_UPLOAD_FILENAME(filename='backup.*', extension='tar.gz', lastdot=False)(fake) + self.assertEqual(rtn, (fake, None)) + fake = gen_fake('README') + rtn = IS_UPLOAD_FILENAME(filename='^README$', extension='^$', case=0)(fake) + self.assertEqual(rtn, (fake, None)) + fake = gen_fake('readme') + rtn = IS_UPLOAD_FILENAME(filename='^README$', extension='^$', case=0)(fake) + self.assertEqual(rtn, (fake, 'Enter valid filename')) + fake = gen_fake('readme') + rtn = IS_UPLOAD_FILENAME(filename='README', case=2)(fake) + self.assertEqual(rtn, (fake, None)) + fake = gen_fake('README') + rtn = IS_UPLOAD_FILENAME(filename='README', case=2)(fake) + self.assertEqual(rtn, (fake, None)) + rtn = IS_UPLOAD_FILENAME(extension='pdf')('example.pdf') + self.assertEqual(rtn, ('example.pdf', 'Enter valid filename')) def test_IS_IPV4(self): rtn = IS_IPV4()('1.2.3.4') @@ -568,320 +891,14 @@ class TestValidators(unittest.TestCase): rtn = IS_IPADDRESS(subnets='invalidsubnet')('2001::8ffa:fe22:b3af') self.assertEqual(rtn, ('2001::8ffa:fe22:b3af', 'invalid subnet provided')) - def test_IS_LENGTH(self): - rtn = IS_LENGTH()('') - self.assertEqual(rtn, ('', None)) - rtn = IS_LENGTH()('1234567890') - self.assertEqual(rtn, ('1234567890', None)) - rtn = IS_LENGTH(maxsize=5, minsize=0)('1234567890') # too long - self.assertEqual(rtn, ('1234567890', 'Enter from 0 to 5 characters')) - rtn = IS_LENGTH(maxsize=50, minsize=20)('1234567890') # too short - self.assertEqual(rtn, ('1234567890', 'Enter from 20 to 50 characters')) - rtn = IS_LENGTH()(None) - self.assertEqual(rtn, (None, None)) - rtn = IS_LENGTH(minsize=0)(None) - self.assertEqual(rtn, (None, None)) - rtn = IS_LENGTH(minsize=1)(None) - self.assertEqual(rtn, (None, 'Enter from 1 to 255 characters')) - rtn = IS_LENGTH(minsize=1)([]) - self.assertEqual(rtn, ([], 'Enter from 1 to 255 characters')) - rtn = IS_LENGTH(minsize=1)([1, 2]) - self.assertEqual(rtn, ([1, 2], None)) - rtn = IS_LENGTH(minsize=1)([1]) - self.assertEqual(rtn, ([1], None)) - # test non utf-8 str - cpstr = u'lálá'.encode('cp1252') - rtn = IS_LENGTH(minsize=4)(cpstr) - self.assertEqual(rtn, (cpstr, None)) - rtn = IS_LENGTH(maxsize=4)(cpstr) - self.assertEqual(rtn, (cpstr, None)) - rtn = IS_LENGTH(minsize=0, maxsize=3)(cpstr) - self.assertEqual(rtn, (cpstr, 'Enter from 0 to 3 characters')) - # test unicode - rtn = IS_LENGTH(2)(u'°2') - self.assertEqual(rtn, ('\xc2\xb02', None)) - rtn = IS_LENGTH(2)(u'°12') - self.assertEqual(rtn, (u'\xb012', 'Enter from 0 to 2 characters')) - # test automatic str() - rtn = IS_LENGTH(minsize=1)(1) - self.assertEqual(rtn, ('1', None)) - rtn = IS_LENGTH(minsize=2)(1) - self.assertEqual(rtn, (1, 'Enter from 2 to 255 characters')) - # test FieldStorage - import cgi - from StringIO import StringIO - a = cgi.FieldStorage() - a.file = StringIO('abc') - rtn = IS_LENGTH(minsize=4)(a) - self.assertEqual(rtn, (a, 'Enter from 4 to 255 characters')) - urlencode_data = "key2=value2x&key3=value3&key4=value4" - urlencode_environ = { - 'CONTENT_LENGTH': str(len(urlencode_data)), - 'CONTENT_TYPE': 'application/x-www-form-urlencoded', - 'QUERY_STRING': 'key1=value1&key2=value2y', - 'REQUEST_METHOD': 'POST', - } - fake_stdin = StringIO(urlencode_data) - fake_stdin.seek(0) - a = cgi.FieldStorage(fp=fake_stdin, environ=urlencode_environ) - rtn = IS_LENGTH(minsize=6)(a) - self.assertEqual(rtn, (a, 'Enter from 6 to 255 characters')) - a = cgi.FieldStorage() - rtn = IS_LENGTH(minsize=6)(a) - self.assertEqual(rtn, (a, 'Enter from 6 to 255 characters')) - rtn = IS_LENGTH(6)(a) - self.assertEqual(rtn, (a, None)) - - def test_IS_LOWER(self): - rtn = IS_LOWER()('ABC') - self.assertEqual(rtn, ('abc', None)) - rtn = IS_LOWER()('Ñ') - self.assertEqual(rtn, ('\xc3\xb1', None)) - - def test_IS_MATCH(self): - rtn = IS_MATCH('.+')('hello') - self.assertEqual(rtn, ('hello', None)) - rtn = IS_MATCH('hell')('hello') - self.assertEqual(rtn, ('hello', None)) - rtn = IS_MATCH('hell.*', strict=False)('hello') - self.assertEqual(rtn, ('hello', None)) - rtn = IS_MATCH('hello')('shello') - self.assertEqual(rtn, ('shello', 'Invalid expression')) - rtn = IS_MATCH('hello', search=True)('shello') - self.assertEqual(rtn, ('shello', None)) - rtn = IS_MATCH('hello', search=True, strict=False)('shellox') - self.assertEqual(rtn, ('shellox', None)) - rtn = IS_MATCH('.*hello.*', search=True, strict=False)('shellox') - self.assertEqual(rtn, ('shellox', None)) - rtn = IS_MATCH('.+')('') - self.assertEqual(rtn, ('', 'Invalid expression')) - rtn = IS_MATCH('hell', strict=True)('hellas') - self.assertEqual(rtn, ('hellas', 'Invalid expression')) - rtn = IS_MATCH('hell$', strict=True)('hellas') - self.assertEqual(rtn, ('hellas', 'Invalid expression')) - rtn = IS_MATCH('^.hell$', strict=True)('shell') - self.assertEqual(rtn, ('shell', None)) - rtn = IS_MATCH(u'hell', is_unicode=True)('àòè') - self.assertEqual(rtn, ('\xc3\xa0\xc3\xb2\xc3\xa8', 'Invalid expression')) - rtn = IS_MATCH(u'hell', is_unicode=True)(u'hell') - self.assertEqual(rtn, (u'hell', None)) - rtn = IS_MATCH('hell', is_unicode=True)(u'hell') - self.assertEqual(rtn, (u'hell', None)) - # regr test for #1044 - rtn = IS_MATCH('hello')(u'\xff') - self.assertEqual(rtn, (u'\xff', 'Invalid expression')) - def test_IS_EQUAL_TO(self): - rtn = IS_EQUAL_TO('aaa')('aaa') - self.assertEqual(rtn, ('aaa', None)) - rtn = IS_EQUAL_TO('aaa')('aab') - self.assertEqual(rtn, ('aab', 'No match')) - - def test_IS_NOT_EMPTY(self): - rtn = IS_NOT_EMPTY()(1) - self.assertEqual(rtn, (1, None)) - rtn = IS_NOT_EMPTY()(0) - self.assertEqual(rtn, (0, None)) - rtn = IS_NOT_EMPTY()('x') - self.assertEqual(rtn, ('x', None)) - rtn = IS_NOT_EMPTY()(' x ') - self.assertEqual(rtn, ('x', None)) - rtn = IS_NOT_EMPTY()(None) - self.assertEqual(rtn, (None, 'Enter a value')) - rtn = IS_NOT_EMPTY()('') - self.assertEqual(rtn, ('', 'Enter a value')) - rtn = IS_NOT_EMPTY()(' ') - self.assertEqual(rtn, ('', 'Enter a value')) - rtn = IS_NOT_EMPTY()(' \n\t') - self.assertEqual(rtn, ('', 'Enter a value')) - rtn = IS_NOT_EMPTY()([]) - self.assertEqual(rtn, ([], 'Enter a value')) - rtn = IS_NOT_EMPTY(empty_regex='def')('def') - self.assertEqual(rtn, ('', 'Enter a value')) - rtn = IS_NOT_EMPTY(empty_regex='de[fg]')('deg') - self.assertEqual(rtn, ('', 'Enter a value')) - rtn = IS_NOT_EMPTY(empty_regex='def')('abc') - self.assertEqual(rtn, ('abc', None)) - - def test_IS_SLUG(self): - rtn = IS_SLUG()('abc123') - self.assertEqual(rtn, ('abc123', None)) - rtn = IS_SLUG()('ABC123') - self.assertEqual(rtn, ('abc123', None)) - rtn = IS_SLUG()('abc-123') - self.assertEqual(rtn, ('abc-123', None)) - rtn = IS_SLUG()('abc--123') - self.assertEqual(rtn, ('abc-123', None)) - rtn = IS_SLUG()('abc 123') - self.assertEqual(rtn, ('abc-123', None)) - rtn = IS_SLUG()('abc\t_123') - self.assertEqual(rtn, ('abc-123', None)) - rtn = IS_SLUG()('-abc-') - self.assertEqual(rtn, ('abc', None)) - rtn = IS_SLUG()('--a--b--_ -c--') - self.assertEqual(rtn, ('a-b-c', None)) - rtn = IS_SLUG()('abc&123') - self.assertEqual(rtn, ('abc123', None)) - rtn = IS_SLUG()('abc&123&def') - self.assertEqual(rtn, ('abc123def', None)) - rtn = IS_SLUG()('ñ') - self.assertEqual(rtn, ('n', None)) - rtn = IS_SLUG(maxlen=4)('abc123') - self.assertEqual(rtn, ('abc1', None)) - rtn = IS_SLUG()('abc_123') - self.assertEqual(rtn, ('abc-123', None)) - rtn = IS_SLUG(keep_underscores=False)('abc_123') - self.assertEqual(rtn, ('abc-123', None)) - rtn = IS_SLUG(keep_underscores=True)('abc_123') - self.assertEqual(rtn, ('abc_123', None)) - rtn = IS_SLUG(check=False)('abc') - self.assertEqual(rtn, ('abc', None)) - rtn = IS_SLUG(check=True)('abc') - self.assertEqual(rtn, ('abc', None)) - rtn = IS_SLUG(check=False)('a bc') - self.assertEqual(rtn, ('a-bc', None)) - rtn = IS_SLUG(check=True)('a bc') - self.assertEqual(rtn, ('a bc', 'Must be slug')) - - def test_IS_STRONG(self): - rtn = IS_STRONG(es=True)('Abcd1234') - self.assertEqual(rtn, ('Abcd1234', - 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|')) - rtn = IS_STRONG(es=True)('Abcd1234!') - self.assertEqual(rtn, ('Abcd1234!', None)) - rtn = IS_STRONG(es=True, entropy=1)('a') - self.assertEqual(rtn, ('a', None)) - rtn = IS_STRONG(es=True, entropy=1, min=2)('a') - self.assertEqual(rtn, ('a', 'Minimum length is 2')) - rtn = IS_STRONG(es=True, entropy=100)('abc123') - self.assertEqual(rtn, ('abc123', 'Entropy (32.35) less than required (100)')) - rtn = IS_STRONG(es=True, entropy=100)('and') - self.assertEqual(rtn, ('and', 'Entropy (14.57) less than required (100)')) - rtn = IS_STRONG(es=True, entropy=100)('aaa') - self.assertEqual(rtn, ('aaa', 'Entropy (14.42) less than required (100)')) - rtn = IS_STRONG(es=True, entropy=100)('a1d') - self.assertEqual(rtn, ('a1d', 'Entropy (15.97) less than required (100)')) - rtn = IS_STRONG(es=True, entropy=100)('añd') - self.assertEqual(rtn, ('a\xc3\xb1d', 'Entropy (18.13) less than required (100)')) - rtn = IS_STRONG()('********') - self.assertEqual(rtn, ('********', None)) - rtn = IS_STRONG(es=True, max=4)('abcde') - self.assertEqual(rtn, - ('abcde', - '|'.join(['Minimum length is 8', - 'Maximum length is 4', - 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|', - 'Must include at least 1 upper case', - 'Must include at least 1 number'])) - ) - rtn = IS_STRONG(es=True)('abcde') - self.assertEqual(rtn, - ('abcde', - '|'.join(['Minimum length is 8', - 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|', - 'Must include at least 1 upper case', - 'Must include at least 1 number'])) - ) - rtn = IS_STRONG(upper=0, lower=0, number=0, es=True)('Abcde1') - self.assertEqual(rtn, - ('Abcde1', - '|'.join(['Minimum length is 8', - 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|', - 'May not include any upper case letters', - 'May not include any lower case letters', - 'May not include any numbers'])) - ) - - def test_IS_TIME(self): - rtn = IS_TIME()('21:30') - self.assertEqual(rtn, (datetime.time(21, 30), None)) - rtn = IS_TIME()('21-30') - self.assertEqual(rtn, (datetime.time(21, 30), None)) - rtn = IS_TIME()('21.30') - self.assertEqual(rtn, (datetime.time(21, 30), None)) - rtn = IS_TIME()('21:30:59') - self.assertEqual(rtn, (datetime.time(21, 30, 59), None)) - rtn = IS_TIME()('5:30') - self.assertEqual(rtn, (datetime.time(5, 30), None)) - rtn = IS_TIME()('5:30 am') - self.assertEqual(rtn, (datetime.time(5, 30), None)) - rtn = IS_TIME()('5:30 pm') - self.assertEqual(rtn, (datetime.time(17, 30), None)) - rtn = IS_TIME()('5:30 whatever') - self.assertEqual(rtn, ('5:30 whatever', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) - rtn = IS_TIME()('5:30 20') - self.assertEqual(rtn, ('5:30 20', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) - rtn = IS_TIME()('24:30') - self.assertEqual(rtn, ('24:30', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) - rtn = IS_TIME()('21:60') - self.assertEqual(rtn, ('21:60', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) - rtn = IS_TIME()('21:30::') - self.assertEqual(rtn, ('21:30::', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) - rtn = IS_TIME()('') - self.assertEqual(rtn, ('', 'Enter time as hh:mm:ss (seconds, am, pm optional)')) - - def test_IS_UPPER(self): - rtn = IS_UPPER()('abc') - self.assertEqual(rtn, ('ABC', None)) - rtn = IS_UPPER()('ñ') - self.assertEqual(rtn, ('\xc3\x91', None)) - def test_IS_JSON(self): - rtn = IS_JSON()('{"a": 100}') - self.assertEqual(rtn, ({u'a': 100}, None)) - rtn = IS_JSON()('spam1234') - self.assertEqual(rtn, ('spam1234', 'Invalid json')) - def test_IS_UPLOAD_FILENAME(self): - import cgi - from StringIO import StringIO - def gen_fake(filename): - formdata_file_data = """ ----123 -Content-Disposition: form-data; name="key2" -value2y ----123 -Content-Disposition: form-data; name="file_attach"; filename="%s" -Content-Type: text/plain -this is the content of the fake file ----123-- -""" % filename - formdata_file_environ = { - 'CONTENT_LENGTH': str(len(formdata_file_data)), - 'CONTENT_TYPE': 'multipart/form-data; boundary=-123', - 'QUERY_STRING': 'key1=value1&key2=value2x', - 'REQUEST_METHOD': 'POST', - } - return cgi.FieldStorage(fp=StringIO(formdata_file_data), environ=formdata_file_environ)['file_attach'] - - fake = gen_fake('example.pdf') - rtn = IS_UPLOAD_FILENAME(extension='pdf')(fake) - self.assertEqual(rtn, (fake, None)) - fake = gen_fake('example.gif') - rtn = IS_UPLOAD_FILENAME(extension='pdf')(fake) - self.assertEqual(rtn, (fake, 'Enter valid filename')) - fake = gen_fake('backup2014.tar.gz') - rtn = IS_UPLOAD_FILENAME(filename='backup.*', extension='tar.gz', lastdot=False)(fake) - self.assertEqual(rtn, (fake, None)) - fake = gen_fake('README') - rtn = IS_UPLOAD_FILENAME(filename='^README$', extension='^$', case=0)(fake) - self.assertEqual(rtn, (fake, None)) - fake = gen_fake('readme') - rtn = IS_UPLOAD_FILENAME(filename='^README$', extension='^$', case=0)(fake) - self.assertEqual(rtn, (fake, 'Enter valid filename')) - fake = gen_fake('readme') - rtn = IS_UPLOAD_FILENAME(filename='README', case=2)(fake) - self.assertEqual(rtn, (fake, None)) - fake = gen_fake('README') - rtn = IS_UPLOAD_FILENAME(filename='README', case=2)(fake) - self.assertEqual(rtn, (fake, None)) - rtn = IS_UPLOAD_FILENAME(extension='pdf')('example.pdf') - self.assertEqual(rtn, ('example.pdf', 'Enter valid filename'))