#!/usr/bin/python import unittest import Cookie import datetime import email.utils import re def get_expires(): # The expires date-time is supposed to be the same as in an email header # RFC-822 (superceeded by RFC-1123) return email.utils.formatdate(usegmt=True) def format_cookie(subs): # Given a dict add cookie components if they're present in the dict cookie = '%(key)s=%(value)s;' % subs if subs.get('domain'): cookie += ' Domain=%(domain)s;' % subs if subs.get('path'): cookie += ' Path=%(path)s;' % subs if subs.get('expires'): cookie += ' Expires=%(expires)s;' % subs if subs.get('max_age'): cookie += ' Max-Age=%(max_age)s;' % subs if subs.get('httponly'): cookie += ' HttpOnly;' if subs.get('secure'): cookie += ' Secure;' return cookie def cookie_load_from_string(cookie_string): # Parse the cookie string, returning a cookie "Morsel" cookies = Cookie.SimpleCookie() cookies.load(cookie_string) return cookies def cookie_load_from_subs(subs): # Form a properly formatted cookie string cookie_string = format_cookie(subs) return cookie_load_from_string(cookie_string) class TestParse(unittest.TestCase): def setUp(self): self.subs = dict(key='color', value='blue', domain='example.com', path='/windy/road', expires=get_expires(), max_age='60', httponly=False, secure=True) def test_key_value(self): cookies = cookie_load_from_subs(self.subs) cookie = cookies[self.subs['key']] self.assertEqual(cookie.key, self.subs['key']) self.assertEqual(cookie.value, self.subs['value']) def test_domain(self): cookies = cookie_load_from_subs(self.subs) cookie = cookies[self.subs['key']] self.assertEqual(cookie['domain'], self.subs['domain']) def test_path(self): cookies = cookie_load_from_subs(self.subs) cookie = cookies[self.subs['key']] self.assertEqual(cookie['path'], self.subs['path']) def test_max_age(self): cookies = cookie_load_from_subs(self.subs) cookie = cookies[self.subs['key']] self.assertEqual(cookie['max-age'], self.subs['max_age']) def test_expires(self): cookies = cookie_load_from_subs(self.subs) cookie = cookies[self.subs['key']] self.assertEqual(cookie['expires'], self.subs['expires']) # I have no idea how one is supposed to query boolean flags to see # if they are set or not (HttpOnly, Secure). A reasonable guess # would be testing to see if Morsel dict has the key for the flag # (if the key is present it's set, if the key is absent it's # not). But the implementation pre-populates the Morsel with every # possible cookie attribute and sets the attributes value to the # empty string. To decide if an attribute is present one is # reduced to testing for the empty string instead of the more # sensible and common practice in Python of testing for the # presence of the attribute or testing to see if it's value is # None. The truth value of the boolean flags is expressed by their # presence or absence in the cookie, if the flag is present it's # True, if it's absent it's False. But because all possible cookie # attributes are pre-populated in the Morsel object one cannot # test for existence, one has to look at the attribute's # value. But the values for the flags are never set, not to True, # False, 1, 0, "True", "False" or any other value. So what value # should the attribute have when testing? # # Hence I have no idea how to test if these flags are set or not, # nor does it even seem possible. Therefore the following tests # for the flags are themselves fundamentally in error because I # can't figure out how the API is supposed to work. def test_httponly(self): cookies = cookie_load_from_subs(self.subs) cookie = cookies[self.subs['key']] # What's the correct test? They're mutually exclusive (see above). self.assertEqual(bool(cookie['httponly']), self.subs['httponly']) self.assertEqual(cookie.has_key('httponly'), self.subs['httponly']) def test_secure(self): cookies = cookie_load_from_subs(self.subs) cookie = cookies[self.subs['key']] # What's the correct test? They're mutually exclusive (see above). self.assertEqual(bool(cookie['secure']), self.subs['secure']) self.assertEqual(cookie.has_key('secure'), self.subs['secure']) # Cookie.py doesn't let you create a cookie with invalid values # so why does it permit parsing a cookie with invalid values? def test_invalid_key(self): with self.assertRaises(Cookie.CookieError): cookie_load_from_string('=blue;') def test_invalid_value(self): with self.assertRaises(Cookie.CookieError): cookie_load_from_string('color=;') def test_invalid_flag(self): with self.assertRaises(Cookie.CookieError): cookie_load_from_string('color=blue; xxx;') def test_invalid_token(self): with self.assertRaises(Cookie.CookieError): cookie_load_from_string('xxx;') class TestCreate(unittest.TestCase): def test_httponly(self): c = Cookie.SimpleCookie() c['color'] = 'blue' # Shouldn't have HttpOnly flag, it was never set self.assertIsNone(re.search('httponly', c.output(header=''), re.IGNORECASE)) # Shouldn't have HttpOnly flag, it's set to False c['color']['httponly'] = False self.assertIsNone(re.search('httponly', c.output(header=''), re.IGNORECASE)) # Should have HttpOnly flag, it's set to True c['color']['httponly'] = True self.assertIsNotNone(re.search('httponly', c.output(header=''), re.IGNORECASE)) def test_secure(self): c = Cookie.SimpleCookie() c['color'] = 'blue' # Shouldn't have Secure flag, it was never set self.assertIsNone(re.search('secure', c.output(header=''), re.IGNORECASE)) # Shouldn't have Secure flag, it's set to False c['color']['secure'] = False self.assertIsNone(re.search('secure', c.output(header=''), re.IGNORECASE)) # Should have Secure flag, it's set to True c['color']['secure'] = True self.assertIsNotNone(re.search('secure', c.output(header=''), re.IGNORECASE)) if __name__ == '__main__': unittest.main()