mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Rewrapped long docstrings and block comments to 79 characters + newline using script from https://github.com/medmunds/autofix-w505.
		
			
				
	
	
		
			410 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			410 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from unittest import TestCase
 | |
| 
 | |
| from django.http import HttpRequest
 | |
| from django.http.request import MediaType
 | |
| 
 | |
| 
 | |
| class MediaTypeTests(TestCase):
 | |
|     def test_empty(self):
 | |
|         for empty_media_type in (None, "", "  "):
 | |
|             with self.subTest(media_type=empty_media_type):
 | |
|                 media_type = MediaType(empty_media_type)
 | |
|                 self.assertEqual(str(media_type), "")
 | |
|                 self.assertEqual(repr(media_type), "<MediaType: >")
 | |
| 
 | |
|     def test_str(self):
 | |
|         self.assertEqual(str(MediaType("*/*; q=0.8")), "*/*; q=0.8")
 | |
|         self.assertEqual(str(MediaType("application/xml")), "application/xml")
 | |
|         self.assertEqual(
 | |
|             str(MediaType("application/xml;type=madeup;q=42")),
 | |
|             "application/xml; type=madeup; q=42",
 | |
|         )
 | |
| 
 | |
|     def test_repr(self):
 | |
|         self.assertEqual(repr(MediaType("*/*; q=0.8")), "<MediaType: */*; q=0.8>")
 | |
|         self.assertEqual(
 | |
|             repr(MediaType("application/xml")),
 | |
|             "<MediaType: application/xml>",
 | |
|         )
 | |
| 
 | |
|     def test_match(self):
 | |
|         tests = [
 | |
|             ("*/*; q=0.8", "*/*"),
 | |
|             ("*/*", "application/json"),
 | |
|             (" */* ", "application/json"),
 | |
|             ("application/*", "application/json"),
 | |
|             ("application/*", "application/*"),
 | |
|             ("application/xml", "application/xml"),
 | |
|             (" application/xml ", "application/xml"),
 | |
|             ("application/xml", " application/xml "),
 | |
|             ("text/vcard; version=4.0", "text/vcard; version=4.0"),
 | |
|             ("text/vcard; version=4.0; q=0.7", "text/vcard; version=4.0"),
 | |
|             ("text/vcard; version=4.0", "text/vcard"),
 | |
|         ]
 | |
|         for accepted_type, mime_type in tests:
 | |
|             with self.subTest(accepted_type, mime_type=mime_type):
 | |
|                 self.assertIs(MediaType(accepted_type).match(mime_type), True)
 | |
| 
 | |
|     def test_no_match(self):
 | |
|         tests = [
 | |
|             # other is falsey.
 | |
|             ("*/*", None),
 | |
|             ("*/*", ""),
 | |
|             # other is malformed.
 | |
|             ("*/*", "; q=0.8"),
 | |
|             # main_type is falsey.
 | |
|             ("/*", "*/*"),
 | |
|             # other.main_type is falsey.
 | |
|             ("*/*", "/*"),
 | |
|             # main sub_type is falsey.
 | |
|             ("application", "application/*"),
 | |
|             # other.sub_type is falsey.
 | |
|             ("application/*", "application"),
 | |
|             # All main and sub types are defined, but there is no match.
 | |
|             ("application/xml", "application/html"),
 | |
|             ("text/vcard; version=4.0", "text/vcard; version=3.0"),
 | |
|             ("text/vcard; q=0.7", "text/vcard; version=3.0"),
 | |
|             ("text/vcard", "text/vcard; version=3.0"),
 | |
|         ]
 | |
|         for accepted_type, mime_type in tests:
 | |
|             with self.subTest(accepted_type, mime_type=mime_type):
 | |
|                 self.assertIs(MediaType(accepted_type).match(mime_type), False)
 | |
| 
 | |
|     def test_params(self):
 | |
|         tests = [
 | |
|             ("text/plain", {}, {}),
 | |
|             ("text/plain;q=0.7", {"q": "0.7"}, {}),
 | |
|             ("text/plain;q=1.5", {"q": "1.5"}, {}),
 | |
|             ("text/plain;q=xyz", {"q": "xyz"}, {}),
 | |
|             ("text/plain;q=0.1234", {"q": "0.1234"}, {}),
 | |
|             ("text/plain;version=2", {"version": "2"}, {"version": "2"}),
 | |
|             (
 | |
|                 "text/plain;version=2;q=0.8",
 | |
|                 {"version": "2", "q": "0.8"},
 | |
|                 {"version": "2"},
 | |
|             ),
 | |
|             (
 | |
|                 "text/plain;q=0.8;version=2",
 | |
|                 {"q": "0.8", "version": "2"},
 | |
|                 {"version": "2"},
 | |
|             ),
 | |
|             (
 | |
|                 "text/plain; charset=UTF-8; q=0.3",
 | |
|                 {"charset": "UTF-8", "q": "0.3"},
 | |
|                 {"charset": "UTF-8"},
 | |
|             ),
 | |
|             (
 | |
|                 "text/plain ; q = 0.5 ; version = 3.0",
 | |
|                 {"q": "0.5", "version": "3.0"},
 | |
|                 {"version": "3.0"},
 | |
|             ),
 | |
|             ("text/plain; format=flowed", {"format": "flowed"}, {"format": "flowed"}),
 | |
|             (
 | |
|                 "text/plain; format=flowed; q=0.4",
 | |
|                 {"format": "flowed", "q": "0.4"},
 | |
|                 {"format": "flowed"},
 | |
|             ),
 | |
|             ("text/*;q=0.2", {"q": "0.2"}, {}),
 | |
|             ("*/json;q=0.9", {"q": "0.9"}, {}),
 | |
|             ("application/json;q=0.9999", {"q": "0.9999"}, {}),
 | |
|             ("text/html;q=0.0001", {"q": "0.0001"}, {}),
 | |
|             ("text/html;q=0", {"q": "0"}, {}),
 | |
|             ("text/html;q=0.", {"q": "0."}, {}),
 | |
|             ("text/html;q=.8", {"q": ".8"}, {}),
 | |
|             ("text/html;q= 0.9", {"q": "0.9"}, {}),
 | |
|             ('text/html ; q = "0.6"', {"q": "0.6"}, {}),
 | |
|         ]
 | |
|         for accepted_type, params, range_params in tests:
 | |
|             media_type = MediaType(accepted_type)
 | |
|             with self.subTest(accepted_type, attr="params"):
 | |
|                 self.assertEqual(media_type.params, params)
 | |
|             with self.subTest(accepted_type, attr="range_params"):
 | |
|                 self.assertEqual(media_type.range_params, range_params)
 | |
| 
 | |
|     def test_quality(self):
 | |
|         tests = [
 | |
|             ("*/*; q=0.8", 0.8),
 | |
|             ("*/*; q=0.0001", 0),
 | |
|             ("*/*; q=0.12345", 0.123),
 | |
|             ("*/*; q=0.1", 0.1),
 | |
|             ("*/*; q=-1", 1),
 | |
|             ("*/*; q=2", 1),
 | |
|             ("*/*; q=h", 1),
 | |
|             ("*/*; q=inf", 1),
 | |
|             ("*/*; q=0", 0),
 | |
|             ("*/*", 1),
 | |
|         ]
 | |
|         for accepted_type, quality in tests:
 | |
|             with self.subTest(accepted_type, quality=quality):
 | |
|                 self.assertEqual(MediaType(accepted_type).quality, quality)
 | |
| 
 | |
|     def test_specificity(self):
 | |
|         tests = [
 | |
|             ("*/*", 0),
 | |
|             ("*/*;q=0.5", 0),
 | |
|             ("text/*", 1),
 | |
|             ("text/*;q=0.5", 1),
 | |
|             ("text/html", 2),
 | |
|             ("text/html;q=1", 2),
 | |
|             ("text/html;q=0.5", 2),
 | |
|             ("text/html;version=5", 3),
 | |
|         ]
 | |
|         for accepted_type, specificity in tests:
 | |
|             with self.subTest(accepted_type, specificity=specificity):
 | |
|                 self.assertEqual(MediaType(accepted_type).specificity, specificity)
 | |
| 
 | |
| 
 | |
| class AcceptHeaderTests(TestCase):
 | |
|     def test_no_headers(self):
 | |
|         """Absence of Accept header defaults to '*/*'."""
 | |
|         request = HttpRequest()
 | |
|         self.assertEqual(
 | |
|             [str(accepted_type) for accepted_type in request.accepted_types],
 | |
|             ["*/*"],
 | |
|         )
 | |
| 
 | |
|     def test_accept_headers(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = (
 | |
|             "text/*,text/html, application/xhtml+xml,application/xml ;q=0.9,*/*;q=0.8,"
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             [str(accepted_type) for accepted_type in request.accepted_types],
 | |
|             [
 | |
|                 "text/html",
 | |
|                 "application/xhtml+xml",
 | |
|                 "text/*",
 | |
|                 "application/xml; q=0.9",
 | |
|                 "*/*; q=0.8",
 | |
|             ],
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             [
 | |
|                 str(accepted_type)
 | |
|                 for accepted_type in request.accepted_types_by_precedence
 | |
|             ],
 | |
|             [
 | |
|                 "text/html",
 | |
|                 "application/xhtml+xml",
 | |
|                 "application/xml; q=0.9",
 | |
|                 "text/*",
 | |
|                 "*/*; q=0.8",
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|     def test_zero_quality(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = "text/*;q=0,text/html"
 | |
|         self.assertEqual(
 | |
|             [str(accepted_type) for accepted_type in request.accepted_types],
 | |
|             ["text/html"],
 | |
|         )
 | |
| 
 | |
|     def test_precedence(self):
 | |
|         """
 | |
|         Taken from https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2.
 | |
|         """
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = (
 | |
|             "text/*, text/plain, text/plain;format=flowed, */*"
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             [
 | |
|                 str(accepted_type)
 | |
|                 for accepted_type in request.accepted_types_by_precedence
 | |
|             ],
 | |
|             [
 | |
|                 "text/plain; format=flowed",
 | |
|                 "text/plain",
 | |
|                 "text/*",
 | |
|                 "*/*",
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|     def test_request_accepts_any(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = "*/*"
 | |
|         self.assertIs(request.accepts("application/json"), True)
 | |
|         self.assertIsNone(request.get_preferred_type([]))
 | |
|         self.assertEqual(
 | |
|             request.get_preferred_type(["application/json", "text/plain"]),
 | |
|             "application/json",
 | |
|         )
 | |
| 
 | |
|     def test_request_accepts_none(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = ""
 | |
|         self.assertIs(request.accepts("application/json"), False)
 | |
|         self.assertEqual(request.accepted_types, [])
 | |
|         self.assertIsNone(
 | |
|             request.get_preferred_type(["application/json", "text/plain"])
 | |
|         )
 | |
| 
 | |
|     def test_request_accepts_some(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = (
 | |
|             "text/html,application/xhtml+xml,application/xml;q=0.9"
 | |
|         )
 | |
|         self.assertIs(request.accepts("text/html"), True)
 | |
|         self.assertIs(request.accepts("application/xhtml+xml"), True)
 | |
|         self.assertIs(request.accepts("application/xml"), True)
 | |
|         self.assertIs(request.accepts("application/json"), False)
 | |
| 
 | |
|     def test_accept_header_priority(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = (
 | |
|             "text/html,application/xml;q=0.9,*/*;q=0.1,text/*;q=0.5"
 | |
|         )
 | |
| 
 | |
|         tests = [
 | |
|             (["text/html", "application/xml"], "text/html"),
 | |
|             (["application/xml", "application/json"], "application/xml"),
 | |
|             (["application/json"], "application/json"),
 | |
|             (["application/json", "text/plain"], "text/plain"),
 | |
|         ]
 | |
|         for types, preferred_type in tests:
 | |
|             with self.subTest(types, preferred_type=preferred_type):
 | |
|                 self.assertEqual(str(request.get_preferred_type(types)), preferred_type)
 | |
| 
 | |
|     def test_accept_header_priority_overlapping_mime(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = "text/*;q=0.8,text/html;q=0.8"
 | |
| 
 | |
|         self.assertEqual(
 | |
|             [str(accepted_type) for accepted_type in request.accepted_types],
 | |
|             [
 | |
|                 "text/html; q=0.8",
 | |
|                 "text/*; q=0.8",
 | |
|             ],
 | |
|         )
 | |
|         self.assertEqual(
 | |
|             [
 | |
|                 str(accepted_type)
 | |
|                 for accepted_type in request.accepted_types_by_precedence
 | |
|             ],
 | |
|             [
 | |
|                 "text/html; q=0.8",
 | |
|                 "text/*; q=0.8",
 | |
|             ],
 | |
|         )
 | |
| 
 | |
|     def test_no_matching_accepted_type(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = "text/html"
 | |
| 
 | |
|         self.assertIsNone(
 | |
|             request.get_preferred_type(["application/json", "text/plain"])
 | |
|         )
 | |
| 
 | |
|     def test_accept_with_param(self):
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = "text/vcard; version=3.0, text/html;q=0.5"
 | |
| 
 | |
|         for media_types, expected in [
 | |
|             (
 | |
|                 [
 | |
|                     "text/vcard; version=4.0",
 | |
|                     "text/vcard; version=3.0",
 | |
|                     "text/vcard",
 | |
|                     "text/directory",
 | |
|                 ],
 | |
|                 "text/vcard; version=3.0",
 | |
|             ),
 | |
|             (["text/vcard; version=4.0", "text/vcard", "text/directory"], None),
 | |
|             (["text/vcard; version=4.0", "text/html"], "text/html"),
 | |
|         ]:
 | |
|             self.assertEqual(request.get_preferred_type(media_types), expected)
 | |
| 
 | |
|     def test_quality_for_media_type_rfc7231(self):
 | |
|         """
 | |
|         Taken from https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2.
 | |
|         """
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = (
 | |
|             "text/*;q=0.3,text/html;q=0.7,text/html;level=1,text/html;level=2;q=0.4,"
 | |
|             "*/*;q=0.5"
 | |
|         )
 | |
| 
 | |
|         for media_type, quality in [
 | |
|             ("text/html;level=1", 1),
 | |
|             ("text/html", 0.7),
 | |
|             ("text/plain", 0.3),
 | |
|             ("image/jpeg", 0.5),
 | |
|             ("text/html;level=2", 0.4),
 | |
|             ("text/html;level=3", 0.7),
 | |
|         ]:
 | |
|             with self.subTest(media_type):
 | |
|                 accepted_media_type = request.accepted_type(media_type)
 | |
|                 self.assertIsNotNone(accepted_media_type)
 | |
|                 self.assertEqual(accepted_media_type.quality, quality)
 | |
| 
 | |
|         for media_types, expected in [
 | |
|             (["text/html", "text/html; level=1"], "text/html; level=1"),
 | |
|             (["text/html; level=2", "text/html; level=3"], "text/html; level=3"),
 | |
|         ]:
 | |
|             self.assertEqual(request.get_preferred_type(media_types), expected)
 | |
| 
 | |
|     def test_quality_for_media_type_rfc9110(self):
 | |
|         """
 | |
|         Taken from
 | |
|         https://www.rfc-editor.org/rfc/rfc9110.html#section-12.5.1-18.
 | |
|         """
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = (
 | |
|             "text/*;q=0.3, text/plain;q=0.7, text/plain;format=flowed, "
 | |
|             "text/plain;format=fixed;q=0.4, */*;q=0.5"
 | |
|         )
 | |
| 
 | |
|         for media_type, quality in [
 | |
|             ("text/plain;format=flowed", 1),
 | |
|             ("text/plain", 0.7),
 | |
|             ("text/html", 0.3),
 | |
|             ("image/jpeg", 0.5),
 | |
|             ("text/plain;format=fixed", 0.4),
 | |
|             ("text/html;level=3", 0.3),  # https://www.rfc-editor.org/errata/eid7138
 | |
|         ]:
 | |
|             with self.subTest(media_type):
 | |
|                 accepted_media_type = request.accepted_type(media_type)
 | |
|                 self.assertIsNotNone(accepted_media_type)
 | |
|                 self.assertEqual(accepted_media_type.quality, quality)
 | |
| 
 | |
|         for media_types, expected in [
 | |
|             (["text/plain", "text/plain; format=flowed"], "text/plain; format=flowed"),
 | |
|             (["text/html", "image/jpeg"], "image/jpeg"),
 | |
|         ]:
 | |
|             self.assertEqual(request.get_preferred_type(media_types), expected)
 | |
| 
 | |
|     def test_quality_breaks_specificity(self):
 | |
|         """
 | |
|         With the same specificity, the quality breaks the tie.
 | |
|         """
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = "text/plain;q=0.5,text/html"
 | |
| 
 | |
|         self.assertEqual(request.accepted_type("text/plain").quality, 0.5)
 | |
|         self.assertEqual(request.accepted_type("text/plain").specificity, 2)
 | |
| 
 | |
|         self.assertEqual(request.accepted_type("text/html").quality, 1)
 | |
|         self.assertEqual(request.accepted_type("text/html").specificity, 2)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             request.get_preferred_type(["text/html", "text/plain"]), "text/html"
 | |
|         )
 | |
| 
 | |
|     def test_quality_over_specificity(self):
 | |
|         """
 | |
|         For media types with the same quality, prefer the more specific type.
 | |
|         """
 | |
|         request = HttpRequest()
 | |
|         request.META["HTTP_ACCEPT"] = "text/*,image/jpeg"
 | |
| 
 | |
|         self.assertEqual(request.accepted_type("text/plain").quality, 1)
 | |
|         self.assertEqual(request.accepted_type("text/plain").specificity, 1)
 | |
| 
 | |
|         self.assertEqual(request.accepted_type("image/jpeg").quality, 1)
 | |
|         self.assertEqual(request.accepted_type("image/jpeg").specificity, 2)
 | |
| 
 | |
|         self.assertEqual(
 | |
|             request.get_preferred_type(["text/plain", "image/jpeg"]), "image/jpeg"
 | |
|         )
 |