PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/regressiontests/httpwrappers/tests.py

https://bitbucket.org/mrshoul/django-hg-git
Python | 582 lines | 509 code | 33 blank | 40 comment | 12 complexity | 553735c46a2f927e5e1b3fa417dd726a MD5 | raw file
Possible License(s): BSD-3-Clause
  1. # -*- encoding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import copy
  4. import os
  5. import pickle
  6. import warnings
  7. from django.core.exceptions import SuspiciousOperation
  8. from django.http import (QueryDict, HttpResponse, HttpResponseRedirect,
  9. HttpResponsePermanentRedirect, HttpResponseNotAllowed,
  10. HttpResponseNotModified, StreamingHttpResponse,
  11. SimpleCookie, BadHeaderError,
  12. parse_cookie)
  13. from django.test import TestCase
  14. from django.utils.encoding import smart_str
  15. from django.utils import six
  16. from django.utils import unittest
  17. class QueryDictTests(unittest.TestCase):
  18. def test_missing_key(self):
  19. q = QueryDict(str(''))
  20. self.assertRaises(KeyError, q.__getitem__, 'foo')
  21. def test_immutability(self):
  22. q = QueryDict(str(''))
  23. self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar')
  24. self.assertRaises(AttributeError, q.setlist, 'foo', ['bar'])
  25. self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar'])
  26. self.assertRaises(AttributeError, q.update, {'foo': 'bar'})
  27. self.assertRaises(AttributeError, q.pop, 'foo')
  28. self.assertRaises(AttributeError, q.popitem)
  29. self.assertRaises(AttributeError, q.clear)
  30. def test_immutable_get_with_default(self):
  31. q = QueryDict(str(''))
  32. self.assertEqual(q.get('foo', 'default'), 'default')
  33. def test_immutable_basic_operations(self):
  34. q = QueryDict(str(''))
  35. self.assertEqual(q.getlist('foo'), [])
  36. if not six.PY3:
  37. self.assertEqual(q.has_key('foo'), False)
  38. self.assertEqual('foo' in q, False)
  39. self.assertEqual(list(six.iteritems(q)), [])
  40. self.assertEqual(list(six.iterlists(q)), [])
  41. self.assertEqual(list(six.iterkeys(q)), [])
  42. self.assertEqual(list(six.itervalues(q)), [])
  43. self.assertEqual(len(q), 0)
  44. self.assertEqual(q.urlencode(), '')
  45. def test_single_key_value(self):
  46. """Test QueryDict with one key/value pair"""
  47. q = QueryDict(str('foo=bar'))
  48. self.assertEqual(q['foo'], 'bar')
  49. self.assertRaises(KeyError, q.__getitem__, 'bar')
  50. self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar')
  51. self.assertEqual(q.get('foo', 'default'), 'bar')
  52. self.assertEqual(q.get('bar', 'default'), 'default')
  53. self.assertEqual(q.getlist('foo'), ['bar'])
  54. self.assertEqual(q.getlist('bar'), [])
  55. self.assertRaises(AttributeError, q.setlist, 'foo', ['bar'])
  56. self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar'])
  57. if not six.PY3:
  58. self.assertTrue(q.has_key('foo'))
  59. self.assertTrue('foo' in q)
  60. if not six.PY3:
  61. self.assertFalse(q.has_key('bar'))
  62. self.assertFalse('bar' in q)
  63. self.assertEqual(list(six.iteritems(q)), [('foo', 'bar')])
  64. self.assertEqual(list(six.iterlists(q)), [('foo', ['bar'])])
  65. self.assertEqual(list(six.iterkeys(q)), ['foo'])
  66. self.assertEqual(list(six.itervalues(q)), ['bar'])
  67. self.assertEqual(len(q), 1)
  68. self.assertRaises(AttributeError, q.update, {'foo': 'bar'})
  69. self.assertRaises(AttributeError, q.pop, 'foo')
  70. self.assertRaises(AttributeError, q.popitem)
  71. self.assertRaises(AttributeError, q.clear)
  72. self.assertRaises(AttributeError, q.setdefault, 'foo', 'bar')
  73. self.assertEqual(q.urlencode(), 'foo=bar')
  74. def test_urlencode(self):
  75. q = QueryDict(str(''), mutable=True)
  76. q['next'] = '/a&b/'
  77. self.assertEqual(q.urlencode(), 'next=%2Fa%26b%2F')
  78. self.assertEqual(q.urlencode(safe='/'), 'next=/a%26b/')
  79. q = QueryDict(str(''), mutable=True)
  80. q['next'] = '/t\xebst&key/'
  81. self.assertEqual(q.urlencode(), 'next=%2Ft%C3%ABst%26key%2F')
  82. self.assertEqual(q.urlencode(safe='/'), 'next=/t%C3%ABst%26key/')
  83. def test_mutable_copy(self):
  84. """A copy of a QueryDict is mutable."""
  85. q = QueryDict(str('')).copy()
  86. self.assertRaises(KeyError, q.__getitem__, "foo")
  87. q['name'] = 'john'
  88. self.assertEqual(q['name'], 'john')
  89. def test_mutable_delete(self):
  90. q = QueryDict(str('')).copy()
  91. q['name'] = 'john'
  92. del q['name']
  93. self.assertFalse('name' in q)
  94. def test_basic_mutable_operations(self):
  95. q = QueryDict(str('')).copy()
  96. q['name'] = 'john'
  97. self.assertEqual(q.get('foo', 'default'), 'default')
  98. self.assertEqual(q.get('name', 'default'), 'john')
  99. self.assertEqual(q.getlist('name'), ['john'])
  100. self.assertEqual(q.getlist('foo'), [])
  101. q.setlist('foo', ['bar', 'baz'])
  102. self.assertEqual(q.get('foo', 'default'), 'baz')
  103. self.assertEqual(q.getlist('foo'), ['bar', 'baz'])
  104. q.appendlist('foo', 'another')
  105. self.assertEqual(q.getlist('foo'), ['bar', 'baz', 'another'])
  106. self.assertEqual(q['foo'], 'another')
  107. if not six.PY3:
  108. self.assertTrue(q.has_key('foo'))
  109. self.assertTrue('foo' in q)
  110. self.assertEqual(list(six.iteritems(q)), [('foo', 'another'), ('name', 'john')])
  111. self.assertEqual(list(six.iterlists(q)), [('foo', ['bar', 'baz', 'another']), ('name', ['john'])])
  112. self.assertEqual(list(six.iterkeys(q)), ['foo', 'name'])
  113. self.assertEqual(list(six.itervalues(q)), ['another', 'john'])
  114. self.assertEqual(len(q), 2)
  115. q.update({'foo': 'hello'})
  116. self.assertEqual(q['foo'], 'hello')
  117. self.assertEqual(q.get('foo', 'not available'), 'hello')
  118. self.assertEqual(q.getlist('foo'), ['bar', 'baz', 'another', 'hello'])
  119. self.assertEqual(q.pop('foo'), ['bar', 'baz', 'another', 'hello'])
  120. self.assertEqual(q.pop('foo', 'not there'), 'not there')
  121. self.assertEqual(q.get('foo', 'not there'), 'not there')
  122. self.assertEqual(q.setdefault('foo', 'bar'), 'bar')
  123. self.assertEqual(q['foo'], 'bar')
  124. self.assertEqual(q.getlist('foo'), ['bar'])
  125. self.assertEqual(q.urlencode(), 'foo=bar&name=john')
  126. q.clear()
  127. self.assertEqual(len(q), 0)
  128. def test_multiple_keys(self):
  129. """Test QueryDict with two key/value pairs with same keys."""
  130. q = QueryDict(str('vote=yes&vote=no'))
  131. self.assertEqual(q['vote'], 'no')
  132. self.assertRaises(AttributeError, q.__setitem__, 'something', 'bar')
  133. self.assertEqual(q.get('vote', 'default'), 'no')
  134. self.assertEqual(q.get('foo', 'default'), 'default')
  135. self.assertEqual(q.getlist('vote'), ['yes', 'no'])
  136. self.assertEqual(q.getlist('foo'), [])
  137. self.assertRaises(AttributeError, q.setlist, 'foo', ['bar', 'baz'])
  138. self.assertRaises(AttributeError, q.setlist, 'foo', ['bar', 'baz'])
  139. self.assertRaises(AttributeError, q.appendlist, 'foo', ['bar'])
  140. if not six.PY3:
  141. self.assertEqual(q.has_key('vote'), True)
  142. self.assertEqual('vote' in q, True)
  143. if not six.PY3:
  144. self.assertEqual(q.has_key('foo'), False)
  145. self.assertEqual('foo' in q, False)
  146. self.assertEqual(list(six.iteritems(q)), [('vote', 'no')])
  147. self.assertEqual(list(six.iterlists(q)), [('vote', ['yes', 'no'])])
  148. self.assertEqual(list(six.iterkeys(q)), ['vote'])
  149. self.assertEqual(list(six.itervalues(q)), ['no'])
  150. self.assertEqual(len(q), 1)
  151. self.assertRaises(AttributeError, q.update, {'foo': 'bar'})
  152. self.assertRaises(AttributeError, q.pop, 'foo')
  153. self.assertRaises(AttributeError, q.popitem)
  154. self.assertRaises(AttributeError, q.clear)
  155. self.assertRaises(AttributeError, q.setdefault, 'foo', 'bar')
  156. self.assertRaises(AttributeError, q.__delitem__, 'vote')
  157. if not six.PY3:
  158. def test_invalid_input_encoding(self):
  159. """
  160. QueryDicts must be able to handle invalid input encoding (in this
  161. case, bad UTF-8 encoding).
  162. This test doesn't apply under Python 3 because the URL is a string
  163. and not a bytestring.
  164. """
  165. q = QueryDict(str(b'foo=bar&foo=\xff'))
  166. self.assertEqual(q['foo'], '\ufffd')
  167. self.assertEqual(q.getlist('foo'), ['bar', '\ufffd'])
  168. def test_pickle(self):
  169. q = QueryDict(str(''))
  170. q1 = pickle.loads(pickle.dumps(q, 2))
  171. self.assertEqual(q == q1, True)
  172. q = QueryDict(str('a=b&c=d'))
  173. q1 = pickle.loads(pickle.dumps(q, 2))
  174. self.assertEqual(q == q1, True)
  175. q = QueryDict(str('a=b&c=d&a=1'))
  176. q1 = pickle.loads(pickle.dumps(q, 2))
  177. self.assertEqual(q == q1, True)
  178. def test_update_from_querydict(self):
  179. """Regression test for #8278: QueryDict.update(QueryDict)"""
  180. x = QueryDict(str("a=1&a=2"), mutable=True)
  181. y = QueryDict(str("a=3&a=4"))
  182. x.update(y)
  183. self.assertEqual(x.getlist('a'), ['1', '2', '3', '4'])
  184. def test_non_default_encoding(self):
  185. """#13572 - QueryDict with a non-default encoding"""
  186. q = QueryDict(str('cur=%A4'), encoding='iso-8859-15')
  187. self.assertEqual(q.encoding, 'iso-8859-15')
  188. self.assertEqual(list(six.iteritems(q)), [('cur', '€')])
  189. self.assertEqual(q.urlencode(), 'cur=%A4')
  190. q = q.copy()
  191. self.assertEqual(q.encoding, 'iso-8859-15')
  192. self.assertEqual(list(six.iteritems(q)), [('cur', '€')])
  193. self.assertEqual(q.urlencode(), 'cur=%A4')
  194. self.assertEqual(copy.copy(q).encoding, 'iso-8859-15')
  195. self.assertEqual(copy.deepcopy(q).encoding, 'iso-8859-15')
  196. class HttpResponseTests(unittest.TestCase):
  197. def test_headers_type(self):
  198. r = HttpResponse()
  199. # The following tests explicitly test types in addition to values
  200. # because in Python 2 u'foo' == b'foo'.
  201. # ASCII unicode or bytes values are converted to native strings.
  202. r['key'] = 'test'
  203. self.assertEqual(r['key'], str('test'))
  204. self.assertIsInstance(r['key'], str)
  205. r['key'] = 'test'.encode('ascii')
  206. self.assertEqual(r['key'], str('test'))
  207. self.assertIsInstance(r['key'], str)
  208. # Latin-1 unicode or bytes values are also converted to native strings.
  209. r['key'] = 'café'
  210. self.assertEqual(r['key'], smart_str('café', 'latin-1'))
  211. self.assertIsInstance(r['key'], str)
  212. r['key'] = 'café'.encode('latin-1')
  213. self.assertEqual(r['key'], smart_str('café', 'latin-1'))
  214. self.assertIsInstance(r['key'], str)
  215. # Other unicode values are MIME-encoded (there's no way to pass them as bytes).
  216. r['key'] = '†'
  217. self.assertEqual(r['key'], str('=?utf-8?b?4oCg?='))
  218. self.assertIsInstance(r['key'], str)
  219. # The response also converts unicode or bytes keys to strings, but requires
  220. # them to contain ASCII
  221. r = HttpResponse()
  222. r['foo'] = 'bar'
  223. l = list(r.items())
  224. self.assertEqual(l[0], ('foo', 'bar'))
  225. self.assertIsInstance(l[0][0], str)
  226. r = HttpResponse()
  227. r[b'foo'] = 'bar'
  228. l = list(r.items())
  229. self.assertEqual(l[0], ('foo', 'bar'))
  230. self.assertIsInstance(l[0][0], str)
  231. r = HttpResponse()
  232. self.assertRaises(UnicodeError, r.__setitem__, 'føø', 'bar')
  233. self.assertRaises(UnicodeError, r.__setitem__, 'føø'.encode('utf-8'), 'bar')
  234. def test_newlines_in_headers(self):
  235. # Bug #10188: Do not allow newlines in headers (CR or LF)
  236. r = HttpResponse()
  237. self.assertRaises(BadHeaderError, r.__setitem__, 'test\rstr', 'test')
  238. self.assertRaises(BadHeaderError, r.__setitem__, 'test\nstr', 'test')
  239. def test_dict_behavior(self):
  240. """
  241. Test for bug #14020: Make HttpResponse.get work like dict.get
  242. """
  243. r = HttpResponse()
  244. self.assertEqual(r.get('test'), None)
  245. def test_non_string_content(self):
  246. #Bug 16494: HttpResponse should behave consistently with non-strings
  247. r = HttpResponse(12345)
  248. self.assertEqual(r.content, b'12345')
  249. #test content via property
  250. r = HttpResponse()
  251. r.content = 12345
  252. self.assertEqual(r.content, b'12345')
  253. def test_iter_content(self):
  254. r = HttpResponse(['abc', 'def', 'ghi'])
  255. self.assertEqual(r.content, b'abcdefghi')
  256. #test iter content via property
  257. r = HttpResponse()
  258. r.content = ['idan', 'alex', 'jacob']
  259. self.assertEqual(r.content, b'idanalexjacob')
  260. r = HttpResponse()
  261. r.content = [1, 2, 3]
  262. self.assertEqual(r.content, b'123')
  263. #test retrieval explicitly using iter (deprecated) and odd inputs
  264. r = HttpResponse()
  265. r.content = ['1', '2', 3, '\u079e']
  266. with warnings.catch_warnings(record=True) as w:
  267. warnings.simplefilter("always", PendingDeprecationWarning)
  268. my_iter = iter(r)
  269. self.assertEqual(w[0].category, PendingDeprecationWarning)
  270. with warnings.catch_warnings(record=True) as w:
  271. warnings.simplefilter("always", PendingDeprecationWarning)
  272. result = list(my_iter)
  273. self.assertEqual(w[0].category, PendingDeprecationWarning)
  274. #'\xde\x9e' == unichr(1950).encode('utf-8')
  275. self.assertEqual(result, [b'1', b'2', b'3', b'\xde\x9e'])
  276. self.assertEqual(r.content, b'123\xde\x9e')
  277. #with Content-Encoding header
  278. r = HttpResponse()
  279. r['Content-Encoding'] = 'winning'
  280. r.content = [b'abc', b'def']
  281. self.assertEqual(r.content, b'abcdef')
  282. r.content = ['\u079e']
  283. self.assertRaises(TypeError if six.PY3 else UnicodeEncodeError,
  284. getattr, r, 'content')
  285. # .content can safely be accessed multiple times.
  286. r = HttpResponse(iter(['hello', 'world']))
  287. self.assertEqual(r.content, r.content)
  288. self.assertEqual(r.content, b'helloworld')
  289. # accessing the iterator works (once) after accessing .content
  290. self.assertEqual(b''.join(r), b'helloworld')
  291. self.assertEqual(b''.join(r), b'')
  292. # accessing .content still works
  293. self.assertEqual(r.content, b'helloworld')
  294. # XXX accessing .content doesn't work if the response was iterated first
  295. # XXX change this when the deprecation completes in HttpResponse
  296. r = HttpResponse(iter(['hello', 'world']))
  297. with warnings.catch_warnings():
  298. warnings.simplefilter("ignore", PendingDeprecationWarning)
  299. self.assertEqual(b''.join(r), b'helloworld')
  300. self.assertEqual(r.content, b'') # not the expected result!
  301. # additional content can be written to the response.
  302. r = HttpResponse(iter(['hello', 'world']))
  303. self.assertEqual(r.content, b'helloworld')
  304. r.write('!')
  305. self.assertEqual(r.content, b'helloworld!')
  306. def test_iterator_isnt_rewound(self):
  307. # Regression test for #13222
  308. r = HttpResponse('abc')
  309. i = iter(r)
  310. self.assertEqual(list(i), [b'abc'])
  311. self.assertEqual(list(i), [])
  312. def test_file_interface(self):
  313. r = HttpResponse()
  314. r.write(b"hello")
  315. self.assertEqual(r.tell(), 5)
  316. r.write("привет")
  317. self.assertEqual(r.tell(), 17)
  318. r = HttpResponse(['abc'])
  319. r.write('def')
  320. self.assertEqual(r.tell(), 6)
  321. self.assertEqual(r.content, b'abcdef')
  322. def test_unsafe_redirect(self):
  323. bad_urls = [
  324. 'data:text/html,<script>window.alert("xss")</script>',
  325. 'mailto:test@example.com',
  326. 'file:///etc/passwd',
  327. ]
  328. for url in bad_urls:
  329. self.assertRaises(SuspiciousOperation,
  330. HttpResponseRedirect, url)
  331. self.assertRaises(SuspiciousOperation,
  332. HttpResponsePermanentRedirect, url)
  333. class HttpResponseSubclassesTests(TestCase):
  334. def test_redirect(self):
  335. response = HttpResponseRedirect('/redirected/')
  336. self.assertEqual(response.status_code, 302)
  337. # Test that standard HttpResponse init args can be used
  338. response = HttpResponseRedirect('/redirected/',
  339. content='The resource has temporarily moved',
  340. content_type='text/html')
  341. self.assertContains(response, 'The resource has temporarily moved', status_code=302)
  342. def test_not_modified(self):
  343. response = HttpResponseNotModified()
  344. self.assertEqual(response.status_code, 304)
  345. # 304 responses should not have content/content-type
  346. with self.assertRaises(AttributeError):
  347. response.content = "Hello dear"
  348. self.assertNotIn('content-type', response)
  349. def test_not_allowed(self):
  350. response = HttpResponseNotAllowed(['GET'])
  351. self.assertEqual(response.status_code, 405)
  352. # Test that standard HttpResponse init args can be used
  353. response = HttpResponseNotAllowed(['GET'],
  354. content='Only the GET method is allowed',
  355. content_type='text/html')
  356. self.assertContains(response, 'Only the GET method is allowed', status_code=405)
  357. class StreamingHttpResponseTests(TestCase):
  358. def test_streaming_response(self):
  359. r = StreamingHttpResponse(iter(['hello', 'world']))
  360. # iterating over the response itself yields bytestring chunks.
  361. chunks = list(r)
  362. self.assertEqual(chunks, [b'hello', b'world'])
  363. for chunk in chunks:
  364. self.assertIsInstance(chunk, six.binary_type)
  365. # and the response can only be iterated once.
  366. self.assertEqual(list(r), [])
  367. # even when a sequence that can be iterated many times, like a list,
  368. # is given as content.
  369. r = StreamingHttpResponse(['abc', 'def'])
  370. self.assertEqual(list(r), [b'abc', b'def'])
  371. self.assertEqual(list(r), [])
  372. # streaming responses don't have a `content` attribute.
  373. self.assertFalse(hasattr(r, 'content'))
  374. # and you can't accidentally assign to a `content` attribute.
  375. with self.assertRaises(AttributeError):
  376. r.content = 'xyz'
  377. # but they do have a `streaming_content` attribute.
  378. self.assertTrue(hasattr(r, 'streaming_content'))
  379. # that exists so we can check if a response is streaming, and wrap or
  380. # replace the content iterator.
  381. r.streaming_content = iter(['abc', 'def'])
  382. r.streaming_content = (chunk.upper() for chunk in r.streaming_content)
  383. self.assertEqual(list(r), [b'ABC', b'DEF'])
  384. # coercing a streaming response to bytes doesn't return a complete HTTP
  385. # message like a regular response does. it only gives us the headers.
  386. r = StreamingHttpResponse(iter(['hello', 'world']))
  387. self.assertEqual(
  388. six.binary_type(r), b'Content-Type: text/html; charset=utf-8')
  389. # and this won't consume its content.
  390. self.assertEqual(list(r), [b'hello', b'world'])
  391. # additional content cannot be written to the response.
  392. r = StreamingHttpResponse(iter(['hello', 'world']))
  393. with self.assertRaises(Exception):
  394. r.write('!')
  395. # and we can't tell the current position.
  396. with self.assertRaises(Exception):
  397. r.tell()
  398. class FileCloseTests(TestCase):
  399. def test_response(self):
  400. filename = os.path.join(os.path.dirname(__file__), 'abc.txt')
  401. # file isn't closed until we close the response.
  402. file1 = open(filename)
  403. r = HttpResponse(file1)
  404. self.assertFalse(file1.closed)
  405. r.close()
  406. self.assertTrue(file1.closed)
  407. # don't automatically close file when we finish iterating the response.
  408. file1 = open(filename)
  409. r = HttpResponse(file1)
  410. self.assertFalse(file1.closed)
  411. with warnings.catch_warnings():
  412. warnings.simplefilter("ignore", PendingDeprecationWarning)
  413. list(r)
  414. self.assertFalse(file1.closed)
  415. r.close()
  416. self.assertTrue(file1.closed)
  417. # when multiple file are assigned as content, make sure they are all
  418. # closed with the response.
  419. file1 = open(filename)
  420. file2 = open(filename)
  421. r = HttpResponse(file1)
  422. r.content = file2
  423. self.assertFalse(file1.closed)
  424. self.assertFalse(file2.closed)
  425. r.close()
  426. self.assertTrue(file1.closed)
  427. self.assertTrue(file2.closed)
  428. def test_streaming_response(self):
  429. filename = os.path.join(os.path.dirname(__file__), 'abc.txt')
  430. # file isn't closed until we close the response.
  431. file1 = open(filename)
  432. r = StreamingHttpResponse(file1)
  433. self.assertFalse(file1.closed)
  434. r.close()
  435. self.assertTrue(file1.closed)
  436. # when multiple file are assigned as content, make sure they are all
  437. # closed with the response.
  438. file1 = open(filename)
  439. file2 = open(filename)
  440. r = StreamingHttpResponse(file1)
  441. r.streaming_content = file2
  442. self.assertFalse(file1.closed)
  443. self.assertFalse(file2.closed)
  444. r.close()
  445. self.assertTrue(file1.closed)
  446. self.assertTrue(file2.closed)
  447. class CookieTests(unittest.TestCase):
  448. def test_encode(self):
  449. """
  450. Test that we don't output tricky characters in encoded value
  451. """
  452. c = SimpleCookie()
  453. c['test'] = "An,awkward;value"
  454. self.assertTrue(";" not in c.output().rstrip(';')) # IE compat
  455. self.assertTrue("," not in c.output().rstrip(';')) # Safari compat
  456. def test_decode(self):
  457. """
  458. Test that we can still preserve semi-colons and commas
  459. """
  460. c = SimpleCookie()
  461. c['test'] = "An,awkward;value"
  462. c2 = SimpleCookie()
  463. c2.load(c.output())
  464. self.assertEqual(c['test'].value, c2['test'].value)
  465. def test_decode_2(self):
  466. """
  467. Test that we haven't broken normal encoding
  468. """
  469. c = SimpleCookie()
  470. c['test'] = b"\xf0"
  471. c2 = SimpleCookie()
  472. c2.load(c.output())
  473. self.assertEqual(c['test'].value, c2['test'].value)
  474. def test_nonstandard_keys(self):
  475. """
  476. Test that a single non-standard cookie name doesn't affect all cookies. Ticket #13007.
  477. """
  478. self.assertTrue('good_cookie' in parse_cookie('good_cookie=yes;bad:cookie=yes').keys())
  479. def test_repeated_nonstandard_keys(self):
  480. """
  481. Test that a repeated non-standard name doesn't affect all cookies. Ticket #15852
  482. """
  483. self.assertTrue('good_cookie' in parse_cookie('a,=b; a,=c; good_cookie=yes').keys())
  484. def test_httponly_after_load(self):
  485. """
  486. Test that we can use httponly attribute on cookies that we load
  487. """
  488. c = SimpleCookie()
  489. c.load("name=val")
  490. c['name']['httponly'] = True
  491. self.assertTrue(c['name']['httponly'])