diff --git a/gluon/tests/__init__.py b/gluon/tests/__init__.py
index 8aedb385..9d66896e 100644
--- a/gluon/tests/__init__.py
+++ b/gluon/tests/__init__.py
@@ -10,6 +10,7 @@ from test_languages import *
from test_router import *
from test_routes import *
from test_storage import *
+from test_serializers import *
from test_template import *
from test_validators import *
from test_utils import *
@@ -22,7 +23,7 @@ if sys.version[:3] == '2.7':
NOSQL = any([name in (os.getenv("DB") or "")
- for name in ("datastore", "mongodb", "imap")])
+ for name in ("datastore", "mongodb", "imap")])
if NOSQL:
from test_dal_nosql import *
diff --git a/gluon/tests/test_html.py b/gluon/tests/test_html.py
index bdc35558..27c7b725 100644
--- a/gluon/tests/test_html.py
+++ b/gluon/tests/test_html.py
@@ -11,6 +11,7 @@ from fix_path import fix_sys_path
fix_sys_path(__file__)
from html import *
+from html import verifyURL
from storage import Storage
@@ -103,6 +104,28 @@ class TestBareHelpers(unittest.TestCase):
def testDIV(self):
self.assertEqual(DIV('<>', _a='1', _b='2').xml(),
'
<>
')
+ # attributes can be updated like in a dict
+ div = DIV('<>', _a='1')
+ div['_b'] = '2'
+ self.assertEqual(div.xml(),
+ '<>
')
+ # also with a mapping
+ div.update(_b=2, _c=3)
+ self.assertEqual(div.xml(),
+ '<>
')
+ # length of the DIV is the number of components
+ self.assertEqual(len(DIV('a', 'bc')), 2)
+ # also if empty, DIV is True in a boolean evaluation
+ self.assertTrue(True if DIV() else False)
+ # parent and siblings
+ a = DIV(SPAN('a'), DIV('b'))
+ s = a.element('span')
+ d = s.parent
+ d['_class'] = 'abc'
+ self.assertEqual(a.xml(), '')
+ self.assertEqual([el.xml() for el in s.siblings()], ['b
'])
+ self.assertEqual(s.sibling().xml(), 'b
')
+ self.assertEqual(s.siblings('a'), [])
def testEM(self):
self.assertEqual(EM('<>', _a='1', _b='2').xml(),
@@ -176,6 +199,9 @@ class TestBareHelpers(unittest.TestCase):
def testP(self):
self.assertEqual(P('<>', _a='1', _b='2').xml(),
'<>
')
+ # test cr2br
+ self.assertEqual(P('a\nb').xml(), 'a\nb
')
+ self.assertEqual(P('a\nb', cr2br=True).xml(), 'a b
')
def testPRE(self):
self.assertEqual(PRE('<>', _a='1', _b='2').xml(),
@@ -186,6 +212,11 @@ class TestBareHelpers(unittest.TestCase):
'''''')
+ self.assertEqual(SCRIPT('<>').xml(),
+ '''''')
+ self.assertEqual(SCRIPT().xml(), '')
def testSELECT(self):
self.assertEqual(SELECT('<>', _a='1', _b='2').xml(),
@@ -217,6 +248,10 @@ class TestBareHelpers(unittest.TestCase):
self.assertEqual(TEXTAREA('<>', _a='1', _b='2').xml(),
'')
+ # override _rows and _cols
+ self.assertEqual(TEXTAREA('<>', _a='1', _b='2', _rows=5, _cols=20).xml(),
+ '')
def testTFOOT(self):
self.assertEqual(TFOOT('<>', _a='1', _b='2').xml(),
@@ -250,6 +285,37 @@ class TestBareHelpers(unittest.TestCase):
self.assertEqual(UL('<>', _a='1', _b='2').xml(),
'')
+ def testXML(self):
+ # sanitization process
+ self.assertEqual(XML('').xml(),
+ '')
+ # with sanitize, data-attributes are not permitted
+ self.assertEqual(XML('', sanitize=True).xml(),
+ 'HelloWorld ')
+ # stringify by default
+ self.assertEqual(XML(1.3), '1.3')
+ self.assertEqual(XML(u'è
').xml(), '\xc3\xa8
')
+ # you can calc len on the class, that equals the xml() and the str()
+ self.assertEqual(len(XML('1.3')), len('1.3'))
+ self.assertEqual(len(XML('1.3').xml()), len('1.3'))
+ self.assertEqual(len(str(XML('1.3'))), len('1.3'))
+ # you can concatenate them to strings (check for __add__ and __radd__ methods)
+ self.assertEqual(XML('a') + 'b', 'ab')
+ self.assertEqual(XML('a') + XML('b'), 'ab')
+ self.assertEqual('a' + XML('b'), 'ab')
+ # you can compare them
+ self.assertEqual(XML('a') == XML('a'), True)
+ # beware that the comparison is made on the XML repr
+ self.assertEqual(XML('', sanitize=True),
+ XML('HelloWorld '))
+
+ def testTAG(self):
+ self.assertEqual(TAG.first(TAG.second('test'), _key=3).xml(),
+ 'test ')
+ # ending in underscore "triggers" style
+ self.assertEqual(TAG.first_(TAG.second('test'), _key=3).xml(),
+ ' ')
+
def testStaticURL(self):
# test response.static_version coupled with response.static_version_urls
self.assertEqual(URL('a', 'c', 'f'), '/a/c/f')
@@ -277,6 +343,7 @@ class TestBareHelpers(unittest.TestCase):
from globals import current
current.request = request
must_return = '/a/c/f'
+ self.assertEqual(URL(), must_return)
self.assertEqual(URL('f'), must_return)
self.assertEqual(URL('c', 'f'), must_return)
self.assertEqual(URL('a', 'c', 'f'), must_return)
@@ -284,15 +351,87 @@ class TestBareHelpers(unittest.TestCase):
def weird():
pass
self.assertEqual(URL('a', 'c', weird), '/a/c/weird')
- self.assertRaises(SyntaxError, URL, *['a','c', 1])
-
+ self.assertRaises(SyntaxError, URL, *['a', 'c', 1])
+ # test signature
+ rtn = URL(
+ a='a', c='c', f='f', args=['x', 'y', 'z'],
+ vars={'p': (1, 3), 'q': 2}, anchor='1', hmac_key='key'
+ )
+ self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f#1')
+ # test _signature exclusion
+ rtn = URL(
+ a='a', c='c', f='f', args=['x', 'y', 'z'],
+ vars={'p': (1, 3), 'q': 2, '_signature': 'abc'},
+ anchor='1', hmac_key='key'
+ )
+ self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f#1')
+ # emulate user_signature
+ current.session = Storage(auth=Storage(hmac_key='key'))
+ self.assertEqual(URL(user_signature=True), '/a/c/f?_signature=c4aed53c08cff08f369dbf8b5ba51889430cf2c2')
+ # hash_vars combination
+ rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key')
+ self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f')
+ rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key', hash_vars=True)
+ self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f')
+ rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key', hash_vars=False)
+ self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=0b5a0702039992aad23c82794b8496e5dcd59a5b')
+ rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key', hash_vars=['p'])
+ self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=5d01b982fd72b39674b012e0288071034e156d7a')
+ rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key', hash_vars='p')
+ self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=5d01b982fd72b39674b012e0288071034e156d7a')
+ # test CRLF detection
+ self.assertRaises(SyntaxError, URL, *['a\n', 'c', 'f'])
+ self.assertRaises(SyntaxError, URL, *['a\r', 'c', 'f'])
+ def testverifyURL(self):
+ r = Storage()
+ r.application = 'a'
+ r.controller = 'c'
+ r.function = 'f'
+ r.extension = 'html'
+ r.env = {}
+ r.get_vars = Storage()
+ # missing signature as request.get_vars returns False
+ rtn = verifyURL(r, 'key')
+ self.assertEqual(rtn, False)
+ # reverse tests from previous testcase with hash_vars combinations
+ r.args = ['x', 'y', 'z']
+ r.get_vars = Storage(p=(1, 3), q=2)
+ # add signature
+ r.get_vars['_signature'] = 'a32530f0d0caa80964bb92aad2bedf8a4486a31f'
+ rtn = verifyURL(r, 'key')
+ self.assertEqual(rtn, True)
+ r.get_vars['_signature'] = 'a32530f0d0caa80964bb92aad2bedf8a4486a31f'
+ rtn = verifyURL(r, 'key', hash_vars=True)
+ self.assertEqual(rtn, True)
+ r.get_vars['_signature'] = '0b5a0702039992aad23c82794b8496e5dcd59a5b'
+ rtn = verifyURL(r, 'key', hash_vars=False)
+ self.assertEqual(rtn, True)
+ r.get_vars['_signature'] = '5d01b982fd72b39674b012e0288071034e156d7a'
+ rtn = verifyURL(r, 'key', hash_vars=['p'])
+ self.assertEqual(rtn, True)
+ r.get_vars['_signature'] = '5d01b982fd72b39674b012e0288071034e156d7a'
+ rtn = verifyURL(r, 'key', hash_vars='p')
+ self.assertEqual(rtn, True)
+ # without session, user_signature returns always False
+ rtn = verifyURL(r, user_signature=True)
+ self.assertEqual(rtn, False)
+ # same goes if you don't use an hmac_key
+ rtn = verifyURL(r)
+ self.assertEqual(rtn, False)
+ # emulate user signature
+ from globals import current
+ current.session = Storage(auth=Storage(hmac_key='key'))
+ r.get_vars['_signature'] = 'a32530f0d0caa80964bb92aad2bedf8a4486a31f'
+ rtn = verifyURL(r, user_signature=True)
+ self.assertEqual(rtn, True)
class TestData(unittest.TestCase):
def testAdata(self):
- self.assertEqual(A('<>', data=dict(abc='', cde='standard'), _a='1', _b='2').xml(),'<> ')
+ self.assertEqual(A('<>', data=dict(abc='', cde='standard'), _a='1', _b='2').xml(),
+ '<> ')
if __name__ == '__main__':
diff --git a/gluon/tests/test_serializers.py b/gluon/tests/test_serializers.py
new file mode 100644
index 00000000..c3324238
--- /dev/null
+++ b/gluon/tests/test_serializers.py
@@ -0,0 +1,67 @@
+#!/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+ Unit tests for gluon.serializers
+"""
+
+import unittest
+from fix_path import fix_sys_path
+import datetime
+import decimal
+
+fix_sys_path(__file__)
+
+from serializers import *
+from storage import Storage
+# careful with the import path 'cause of isinstance() checks
+from gluon.languages import translator
+from gluon.html import SPAN
+
+
+class TestSerializers(unittest.TestCase):
+
+ def testJSON(self):
+ # the main and documented "way" is to use the json() function
+ # it has a few corner-cases that make json() be somewhat
+ # different from the standard buyt being compliant
+ # it's just a matter of conventions
+
+ # incompatible spacing, newer simplejson already account
+ # for this but it's still better to remember
+ weird = {'JSON': u"ro" + u'\u2028' + u'ck' + u'\u2029' + u's!'}
+ rtn = json(weird)
+ self.assertEqual(rtn, u'{"JSON": "ro\\u2028ck\\u2029s!"}')
+ # date, datetime, time strictly as strings in isoformat, minus the T
+ objs = [
+ datetime.datetime(2014, 1, 1, 12, 15, 35),
+ datetime.date(2014, 1, 1),
+ datetime.time(12, 15, 35)
+ ]
+ iso_objs = [obj.isoformat()[:19].replace('T', ' ') for obj in objs]
+ json_objs = [json(obj) for obj in objs]
+ json_web2pyfied = [json(obj) for obj in iso_objs]
+ self.assertEqual(json_objs, json_web2pyfied)
+ # int or long int()ified
+ self.assertEqual(json(1), json(1L))
+ # decimal stringified
+ obj = {'a': decimal.Decimal('4.312312312312')}
+ self.assertEqual(json(obj), u'{"a": "4.312312312312"}')
+ # lazyT translated
+ T = translator('', 'en')
+ lazy_translation = T('abc')
+ self.assertEqual(json(lazy_translation), u'"abc"')
+ # html helpers are xml()ed before too
+ self.assertEqual(json(SPAN('abc')), u'"abc "')
+ # unicode keys make a difference with loads_json
+ base = {u'è': 1, 'b': 2}
+ base_enc = json(base)
+ base_load = loads_json(base_enc)
+ self.assertTrue(base == base_load)
+ # if unicode_keys is false, the standard behaviour is assumed
+ base_load = loads_json(base_enc, unicode_keys=False)
+ self.assertFalse(base == base_load)
+
+
+if __name__ == '__main__':
+ unittest.main()