import re import warnings import pytest from webob.acceptparse import ( Accept, AcceptCharset, AcceptCharsetInvalidHeader, AcceptCharsetNoHeader, AcceptCharsetValidHeader, AcceptEncoding, AcceptEncodingInvalidHeader, AcceptEncodingNoHeader, AcceptEncodingValidHeader, AcceptInvalidHeader, AcceptLanguage, AcceptLanguageInvalidHeader, AcceptLanguageNoHeader, AcceptLanguageValidHeader, AcceptNoHeader, AcceptValidHeader, MIMEAccept, _item_n_weight_re, _list_1_or_more__compiled_re, accept_charset_property, accept_encoding_property, accept_language_property, accept_property, create_accept_charset_header, create_accept_encoding_header, create_accept_header, create_accept_language_header, ) from webob.request import Request IGNORE_BEST_MATCH = "ignore:.*best_match.*" IGNORE_QUALITY = "ignore:.*quality.*" IGNORE_CONTAINS = "ignore:.*__contains__.*" IGNORE_ITER = "ignore:.*__iter__.*" IGNORE_MIMEACCEPT = "ignore:.*MIMEAccept.*" class Test_ItemNWeightRe: @pytest.mark.parametrize( "header_value", [ "q=", "q=1", ";q", ";q=", ";q=1", "foo;", "foo;q", "foo;q1", "foo;q=", "foo;q=-1", "foo;q=2", "foo;q=1.001", "foo;q=0.0001", "foo;q=00", "foo;q=01", "foo;q=00.1", "foo,q=0.1", "foo;q =1", "foo;q= 1", ], ) def test_invalid(self, header_value): regex = _item_n_weight_re(item_re="foo") assert re.match("^" + regex + "$", header_value, re.VERBOSE) is None @pytest.mark.parametrize( "header_value, groups", [ ("foo", ("foo", None)), ("foo;q=0", ("foo", "0")), ("foo;q=0.0", ("foo", "0.0")), ("foo;q=0.00", ("foo", "0.00")), ("foo;q=0.000", ("foo", "0.000")), ("foo;q=1", ("foo", "1")), ("foo;q=1.0", ("foo", "1.0")), ("foo;q=1.00", ("foo", "1.00")), ("foo;q=1.000", ("foo", "1.000")), ("foo;q=0.1", ("foo", "0.1")), ("foo;q=0.87", ("foo", "0.87")), ("foo;q=0.382", ("foo", "0.382")), ("foo;Q=0.382", ("foo", "0.382")), ("foo ;Q=0.382", ("foo", "0.382")), ("foo; Q=0.382", ("foo", "0.382")), ("foo ; Q=0.382", ("foo", "0.382")), ], ) def test_valid(self, header_value, groups): regex = _item_n_weight_re(item_re="foo") assert re.match("^" + regex + "$", header_value, re.VERBOSE).groups() == groups class Test_List1OrMoreCompiledRe: @pytest.mark.parametrize( "header_value", [ # RFC 7230 Section 7 ",", ", ,", # RFC 7230 Errata ID: 4169 "foo , ,bar,charlie ", # Our tests " foo , ,bar,charlie", " ,foo , ,bar,charlie", ",foo , ,bar,charlie, ", "\tfoo , ,bar,charlie", "\t,foo , ,bar,charlie", ",foo , ,bar,charlie\t", ",foo , ,bar,charlie,\t", ], ) def test_invalid(self, header_value): regex = _list_1_or_more__compiled_re(element_re="([a-z]+)") assert regex.match(header_value) is None @pytest.mark.parametrize( "header_value", [ # RFC 7230 Section 7 "foo,bar", "foo, bar,", # RFC 7230 Errata ID: 4169 "foo , ,bar,charlie", # Our tests "foo , ,bar,charlie", ",foo , ,bar,charlie", ",foo , ,bar,charlie,", ",\t ,,, \t \t, ,\t\t\t,foo \t\t,, bar, ,\tcharlie \t,, ,", ], ) def test_valid(self, header_value): regex = _list_1_or_more__compiled_re(element_re="([a-z]+)") assert regex.match(header_value) class TestAccept: @pytest.mark.parametrize( "value", [ ", ", ", , ", "noslash", "/", "text/", "/html", "text/html;", "text/html;param", "text/html;param=", "text/html ;param=val;", "text/html; param=val;", "text/html;param=val;", "text/html;param=\x19", "text/html;param=\x22", "text/html;param=\x5c", "text/html;param=\x7f", r'text/html;param="\"', r'text/html;param="\\\"', r'text/html;param="\\""', 'text/html;param="\\\x19"', 'text/html;param="\\\x7f"', "text/html;q", "text/html;q=", "text/html;q=-1", "text/html;q=2", "text/html;q=1.001", "text/html;q=0.0001", "text/html;q=00", "text/html;q=01", "text/html;q=00.1", "text/html,q=0.1", "text/html;q =1", "text/html;q= 1", "text/html;q=1;", "text/html;param;q=1", "text/html;q=1;extparam;", "text/html;q=1;extparam=val;", 'text/html;q=1;extparam="val";', 'text/html;q=1;extparam="', 'text/html;q=1;extparam="val', 'text/html;q=1;extparam=val"', "text/html;q=1;extparam=\x19", "text/html;q=1;extparam=\x22", "text/html;q=1;extparam=\x5c", "text/html;q=1;extparam=\x7f", r'text/html;q=1;extparam="\"', r'text/html;q=1;extparam="\\\"', r'text/html;q=1;extparam="\\""', 'text/html;q=1;extparam="\\\x19"', 'text/html;q=1;extparam="\\\x7f"', "text/html;param=\x19;q=1;extparam", "text/html;param=val;q=1;extparam=\x19", ], ) def test_parse__invalid_header(self, value): with pytest.raises(ValueError): AcceptValidHeader.parse(value=value) @pytest.mark.parametrize( "value, expected_list", [ # Examples from RFC 7231, Section 5.3.2 "Accept": ( "audio/*; q=0.2, audio/basic", [("audio/*", 0.2, [], []), ("audio/basic", 1.0, [], [])], ), ( "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c", [ ("text/plain", 0.5, [], []), ("text/html", 1.0, [], []), ("text/x-dvi", 0.8, [], []), ("text/x-c", 1.0, [], []), ], ), ( "text/*, text/plain, text/plain;format=flowed, */*", [ ("text/*", 1.0, [], []), ("text/plain", 1.0, [], []), ("text/plain;format=flowed", 1.0, [("format", "flowed")], []), ("*/*", 1.0, [], []), ], ), ( "text/*;q=0.3, text/html;q=0.7, text/html;level=1, " "text/html;level=2;q=0.4, */*;q=0.5", [ ("text/*", 0.3, [], []), ("text/html", 0.7, [], []), ("text/html;level=1", 1.0, [("level", "1")], []), ("text/html;level=2", 0.4, [("level", "2")], []), ("*/*", 0.5, [], []), ], ), # Our tests ("", []), (",", []), (", ,", []), ( "*/*, text/*, text/html", [ ("*/*", 1.0, [], []), ("text/*", 1.0, [], []), ("text/html", 1.0, [], []), ], ), # It does not seem from RFC 7231, section 5.3.2 "Accept" that the '*' # in a range like '*/html' was intended to have any special meaning # (the section lists '*/*', 'type/*' and 'type/subtype', but not # '*/subtype'). However, because type and subtype are tokens (section # 3.1.1.1), and a token may contain '*'s, '*/subtype' is valid. ("*/html", [("*/html", 1.0, [], [])]), ( 'text/html \t;\t param1=val1\t; param2="val2" ' + r'; param3="\"\\\\"', [ ( r'text/html;param1=val1;param2=val2;param3="\"\\\\"', 1.0, [("param1", "val1"), ("param2", "val2"), ("param3", r'"\\')], [], ) ], ), ( "text/html;param=!#$%&'*+-.^_`|~09AZaz", [ ( "text/html;param=!#$%&'*+-.^_`|~09AZaz", 1.0, [("param", "!#$%&'*+-.^_`|~09AZaz")], [], ) ], ), ('text/html;param=""', [('text/html;param=""', 1.0, [("param", "")], [])]), ( 'text/html;param="\t \x21\x23\x24\x5a\x5b\x5d\x5e\x7d\x7e"', [ ( 'text/html;param="\t \x21\x23\x24\x5a\x5b\x5d\x5e\x7d\x7e"', 1.0, [("param", "\t \x21\x23\x24\x5a\x5b\x5d\x5e\x7d\x7e")], [], ) ], ), ( 'text/html;param="\x80\x81\xfe\xff\\\x22\\\x5c"', [ ( 'text/html;param="\x80\x81\xfe\xff\\\x22\\\x5c"', 1.0, [("param", "\x80\x81\xfe\xff\x22\x5c")], [], ) ], ), ( 'text/html;param="\\\t\\ \\\x21\\\x7e\\\x80\\\xff"', [ ( 'text/html;param="\t \x21\x7e\x80\xff"', 1.0, [("param", "\t \x21\x7e\x80\xff")], [], ) ], ), ( "text/html;param='val'", # This makes it look like the media type parameter value could be # surrounded with single quotes instead of double quotes, but the # single quotes are actually part of the media type parameter value # token [("text/html;param='val'", 1.0, [("param", "'val'")], [])], ), ("text/html;q=0.9", [("text/html", 0.9, [], [])]), ("text/html;q=0", [("text/html", 0.0, [], [])]), ("text/html;q=0.0", [("text/html", 0.0, [], [])]), ("text/html;q=0.00", [("text/html", 0.0, [], [])]), ("text/html;q=0.000", [("text/html", 0.0, [], [])]), ("text/html;q=1", [("text/html", 1.0, [], [])]), ("text/html;q=1.0", [("text/html", 1.0, [], [])]), ("text/html;q=1.00", [("text/html", 1.0, [], [])]), ("text/html;q=1.000", [("text/html", 1.0, [], [])]), ("text/html;q=0.1", [("text/html", 0.1, [], [])]), ("text/html;q=0.87", [("text/html", 0.87, [], [])]), ("text/html;q=0.382", [("text/html", 0.382, [], [])]), ("text/html;Q=0.382", [("text/html", 0.382, [], [])]), ("text/html ;Q=0.382", [("text/html", 0.382, [], [])]), ("text/html; Q=0.382", [("text/html", 0.382, [], [])]), ("text/html ; Q=0.382", [("text/html", 0.382, [], [])]), ("text/html;q=0.9;q=0.8", [("text/html", 0.9, [], [("q", "0.8")])]), ( "text/html;q=1;q=1;q=1", [("text/html", 1.0, [], [("q", "1"), ("q", "1")])], ), ( 'text/html;q=0.9;extparam1;extparam2=val2;extparam3="val3"', [ ( "text/html", 0.9, [], ["extparam1", ("extparam2", "val2"), ("extparam3", "val3")], ) ], ), ( "text/html;q=1;extparam=!#$%&'*+-.^_`|~09AZaz", [("text/html", 1.0, [], [("extparam", "!#$%&'*+-.^_`|~09AZaz")])], ), ('text/html;q=1;extparam=""', [("text/html", 1.0, [], [("extparam", "")])]), ( 'text/html;q=1;extparam="\t \x21\x23\x24\x5a\x5b\x5d\x5e\x7d\x7e"', [ ( "text/html", 1.0, [], [("extparam", "\t \x21\x23\x24\x5a\x5b\x5d\x5e\x7d\x7e")], ) ], ), ( 'text/html;q=1;extparam="\x80\x81\xfe\xff\\\x22\\\x5c"', [("text/html", 1.0, [], [("extparam", "\x80\x81\xfe\xff\x22\x5c")])], ), ( 'text/html;q=1;extparam="\\\t\\ \\\x21\\\x7e\\\x80\\\xff"', [("text/html", 1.0, [], [("extparam", "\t \x21\x7e\x80\xff")])], ), ( "text/html;q=1;extparam='val'", # This makes it look like the extension parameter value could be # surrounded with single quotes instead of double quotes, but the # single quotes are actually part of the extension parameter value # token [("text/html", 1.0, [], [("extparam", "'val'")])], ), ( 'text/html;param1="val1";param2=val2;q=0.9;extparam1="val1"' ";extparam2;extparam3=val3", [ ( "text/html;param1=val1;param2=val2", 0.9, [("param1", "val1"), ("param2", "val2")], [("extparam1", "val1"), "extparam2", ("extparam3", "val3")], ) ], ), ( ", ,, a/b \t;\t p1=1 ;\t\tp2=2 ; q=0.6\t \t;\t\t e1\t; e2, ,", [("a/b;p1=1;p2=2", 0.6, [("p1", "1"), ("p2", "2")], ["e1", "e2"])], ), ( ( ",\t , a/b;q=1;e1;e2=v2 \t,\t\t c/d, e/f;p1=v1;q=0;e1, " + "g/h;p1=v1\t ;\t\tp2=v2;q=0.5 \t," ), [ ("a/b", 1.0, [], ["e1", ("e2", "v2")]), ("c/d", 1.0, [], []), ("e/f;p1=v1", 0.0, [("p1", "v1")], ["e1"]), ("g/h;p1=v1;p2=v2", 0.5, [("p1", "v1"), ("p2", "v2")], []), ], ), ], ) def test_parse__valid_header(self, value, expected_list): returned = AcceptValidHeader.parse(value=value) list_of_returned = list(returned) assert list_of_returned == expected_list @pytest.mark.parametrize( "offer, expected_return, expected_str", [ ["text/html", ("text", "html", ()), "text/html"], [ "text/html;charset=utf8", ("text", "html", (("charset", "utf8"),)), "text/html;charset=utf8", ], [ "text/html;charset=utf8;x-version=1", ("text", "html", (("charset", "utf8"), ("x-version", "1"))), "text/html;charset=utf8;x-version=1", ], [ "text/HtMl;cHaRseT=UtF-8;X-Version=1", ("text", "html", (("charset", "UtF-8"), ("x-version", "1"))), "text/html;charset=UtF-8;x-version=1", ], ], ) def test_parse_offer__valid(self, offer, expected_return, expected_str): result = Accept.parse_offer(offer) assert result == expected_return assert str(result) == expected_str assert result is Accept.parse_offer(result) @pytest.mark.parametrize( "offer", [ "", "foo", "foo/bar/baz", "*/plain", "*/plain;charset=utf8", "*/plain;charset=utf8;x-version=1", "*/*;charset=utf8", "text/*;charset=utf8", "text/*", "*/*", ], ) def test_parse_offer__invalid(self, offer): with pytest.raises(ValueError): Accept.parse_offer(offer) class TestAcceptValidHeader: def test_parse__inherited(self): returned = AcceptValidHeader.parse( value=( ",\t , a/b;q=1;e1;e2=v2 \t,\t\t c/d, e/f;p1=v1;q=0;e1, " + "g/h;p1=v1\t ;\t\tp2=v2;q=0.5 \t," ) ) list_of_returned = list(returned) assert list_of_returned == [ ("a/b", 1.0, [], ["e1", ("e2", "v2")]), ("c/d", 1.0, [], []), ("e/f;p1=v1", 0.0, [("p1", "v1")], ["e1"]), ("g/h;p1=v1;p2=v2", 0.5, [("p1", "v1"), ("p2", "v2")], []), ] @pytest.mark.parametrize( "header_value", [", ", "text/html;param=val;q=1;extparam=\x19"] ) def test___init___invalid_header(self, header_value): with pytest.raises(ValueError): AcceptValidHeader(header_value=header_value) def test___init___valid_header(self): header_value = ( ",\t , a/b;q=1;e1;e2=v2 \t,\t\t c/d, e/f;p1=v1;q=0;e1, " + "g/h;p1=v1\t ;\t\tp2=v2;q=0.5 \t," ) instance = AcceptValidHeader(header_value=header_value) assert instance.header_value == header_value assert instance.parsed == [ ("a/b", 1.0, [], ["e1", ("e2", "v2")]), ("c/d", 1.0, [], []), ("e/f;p1=v1", 0.0, [("p1", "v1")], ["e1"]), ("g/h;p1=v1;p2=v2", 0.5, [("p1", "v1"), ("p2", "v2")], []), ] assert instance._parsed_nonzero == [ ("a/b", 1.0, [], ["e1", ("e2", "v2")]), ("c/d", 1.0, [], []), ("g/h;p1=v1;p2=v2", 0.5, [("p1", "v1"), ("p2", "v2")], []), ] assert isinstance(instance, Accept) def test___add___None(self): left_operand = AcceptValidHeader(header_value="text/html") result = left_operand + None assert isinstance(result, AcceptValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize( "right_operand", [ ", ", [", "], (", ",), {", ": 1.0}, {", ;level=1": (1.0, ";e1=1")}, "a/b, c/d;q=1;e1;", ["a/b", "c/d;q=1;e1;"], ("a/b", "c/d;q=1;e1;"), {"a/b": 1.0, "cd": 1.0}, {"a/b": (1.0, ";e1=1"), "c/d": (1.0, ";e2=2;")}, ], ) def test___add___invalid_value(self, right_operand): left_operand = AcceptValidHeader(header_value="text/html") result = left_operand + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize("str_", [", ", "a/b, c/d;q=1;e1;"]) def test___add___other_type_with_invalid___str__(self, str_): left_operand = AcceptValidHeader(header_value="text/html") class Other: def __str__(self): return str_ right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize("value", ["", [], (), {}]) def test___add___valid_empty_value(self, value): left_operand = AcceptValidHeader(header_value=",\t ,i/j, k/l;q=0.333,") result = left_operand + value assert isinstance(result, AcceptValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand def test___add___other_type_with_valid___str___empty(self): left_operand = AcceptValidHeader(header_value=",\t ,i/j, k/l;q=0.333,") class Other: def __str__(self): return "" result = left_operand + Other() assert isinstance(result, AcceptValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize( "value, value_as_header", [ # str ( "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of strs ( ["a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 3-item tuples, with extension parameters ( [ ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 2-item tuples, without extension parameters ( [("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # list of a mixture of strs, 3-item tuples and 2-item tuples ( [ ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of strs ( ("a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 3-item tuples, with extension parameters ( ( ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 2-item tuples, without extension parameters ( (("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # tuple of a mixture of strs, 3-item tuples and 2-item tuples ( ( ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # dict ( {"a/b": (0.5, ";e1=1"), "c/d": 0.0, "e/f;p1=1": (1.0, ";e1=1;e2=2")}, "e/f;p1=1;q=1;e1=1;e2=2, a/b;q=0.5;e1=1, c/d;q=0", ), ], ) def test___add___valid_value(self, value, value_as_header): header = ",\t ,i/j, k/l;q=0.333," result = AcceptValidHeader(header_value=header) + value assert isinstance(result, AcceptValidHeader) assert result.header_value == header + ", " + value_as_header def test___add___other_type_with_valid___str___not_empty(self): header = ",\t ,i/j, k/l;q=0.333," class Other: def __str__(self): return "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" right_operand = Other() result = AcceptValidHeader(header_value=header) + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == header + ", " + str(right_operand) def test___add___AcceptValidHeader_header_value_empty(self): left_operand = AcceptValidHeader( header_value="a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" ) right_operand = AcceptValidHeader(header_value="") result = left_operand + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand def test___add___AcceptValidHeader_header_value_not_empty(self): left_operand = AcceptValidHeader( header_value="a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" ) right_operand = AcceptValidHeader(header_value=",\t ,i/j, k/l;q=0.333,") result = left_operand + right_operand assert isinstance(result, AcceptValidHeader) assert ( result.header_value == left_operand.header_value + ", " + right_operand.header_value ) def test___add___AcceptNoHeader(self): valid_header_instance = AcceptValidHeader(header_value="a/b") result = valid_header_instance + AcceptNoHeader() assert isinstance(result, AcceptValidHeader) assert result.header_value == valid_header_instance.header_value assert result is not valid_header_instance @pytest.mark.parametrize("header_value", [", ", 'a/b;p1=1;p2=2;q=0.8;e1;e2="']) def test___add___AcceptInvalidHeader(self, header_value): valid_header_instance = AcceptValidHeader(header_value="a/b") result = valid_header_instance + AcceptInvalidHeader(header_value=header_value) assert isinstance(result, AcceptValidHeader) assert result.header_value == valid_header_instance.header_value assert result is not valid_header_instance def test___bool__(self): instance = AcceptValidHeader(header_value="type/subtype") returned = bool(instance) assert returned is True @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): accept = AcceptValidHeader("A/a, B/b, C/c") assert "A/a" in accept assert "A/*" in accept assert "*/a" in accept assert "A/b" not in accept assert "B/a" not in accept for mask in ["*/*", "text/html", "TEXT/HTML"]: assert "text/html" in AcceptValidHeader(mask) @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptValidHeader( header_value=( "text/plain; q=0.5, text/html; q=0, text/x-dvi; q=0.8, " "text/x-c" ) ) assert list(instance) == ["text/x-c", "text/x-dvi", "text/plain"] def test___radd___None(self): right_operand = AcceptValidHeader(header_value="a/b") result = None + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize( "left_operand", [ ", ", [", "], (", ",), {", ": 1.0}, {", ;level=1": (1.0, ";e1=1")}, "a/b, c/d;q=1;e1;", ["a/b", "c/d;q=1;e1;"], ("a/b", "c/d;q=1;e1;"), {"a/b": 1.0, "cd": 1.0}, {"a/b": (1.0, ";e1=1"), "c/d": (1.0, ";e2=2;")}, ], ) def test___radd___invalid_value(self, left_operand): right_operand = AcceptValidHeader(header_value="a/b") result = left_operand + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize("str_", [", ", "a/b, c/d;q=1;e1;"]) def test___radd___other_type_with_invalid___str__(self, str_): right_operand = AcceptValidHeader(header_value="a/b") class Other: def __str__(self): return str_ result = Other() + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize("value", ["", [], (), {}]) def test___radd___valid_empty_value(self, value): right_operand = AcceptValidHeader(header_value="a/b") result = value + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___radd___other_type_with_valid___str___empty(self): right_operand = AcceptValidHeader(header_value=",\t ,i/j, k/l;q=0.333,") class Other: def __str__(self): return "" result = Other() + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize( "value, value_as_header", [ # str ( "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of strs ( ["a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 3-item tuples, with extension parameters ( [ ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 2-item tuples, without extension parameters ( [("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # list of a mixture of strs, 3-item tuples and 2-item tuples ( [ ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of strs ( ("a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 3-item tuples, with extension parameters ( ( ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 2-item tuples, without extension parameters ( (("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # tuple of a mixture of strs, 3-item tuples and 2-item tuples ( ( ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # dict ( {"a/b": (0.5, ";e1=1"), "c/d": 0.0, "e/f;p1=1": (1.0, ";e1=1;e2=2")}, "e/f;p1=1;q=1;e1=1;e2=2, a/b;q=0.5;e1=1, c/d;q=0", ), ], ) def test___radd___valid_non_empty_value(self, value, value_as_header): header = ",\t ,i/j, k/l;q=0.333," result = value + AcceptValidHeader(header_value=header) assert isinstance(result, AcceptValidHeader) assert result.header_value == value_as_header + ", " + header def test___radd___other_type_with_valid___str___not_empty(self): header = ",\t ,i/j, k/l;q=0.333," class Other: def __str__(self): return "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" left_operand = Other() result = left_operand + AcceptValidHeader(header_value=header) assert isinstance(result, AcceptValidHeader) assert result.header_value == str(left_operand) + ", " + header @pytest.mark.parametrize( "header_value, expected_returned", [ ("", ""), ( r',,text/html ; p1="\"\1\"" ; q=0.50; e1=1 ;e2 , text/plain ,', r"""", ), ( ',\t, a/b ; p1=1 ; p2=2 ;\t q=0.20 ;\te1="\\"\\1\\""\t; e2 ; ' + "e3=3, c/d ,,", r"""", ), ], ) def test___repr__(self, header_value, expected_returned): instance = AcceptValidHeader(header_value=header_value) assert repr(instance) == expected_returned @pytest.mark.parametrize( "header_value, expected_returned", [ ("", ""), ( r',,text/html ; p1="\"\1\"" ; q=0.50; e1=1 ;e2 , text/plain ,', r'text/html;p1="\"1\"";q=0.5;e1=1;e2, text/plain', ), ( ',\t, a/b ; p1=1 ; p2=2 ;\t q=0.20 ;\te1="\\"\\1\\""\t; e2 ; ' + "e3=3, c/d ,,", 'a/b;p1=1;p2=2;q=0.2;e1="\\"1\\"";e2;e3=3, c/d', ), ], ) def test___str__(self, header_value, expected_returned): instance = AcceptValidHeader(header_value=header_value) assert str(instance) == expected_returned def test__old_match(self): accept = AcceptValidHeader("image/jpg") assert accept._old_match("image/jpg", "image/jpg") assert accept._old_match("image/*", "image/jpg") assert accept._old_match("*/*", "image/jpg") assert not accept._old_match("text/html", "image/jpg") mismatches = [ ("B/b", "A/a"), ("B/b", "B/a"), ("B/b", "A/b"), ("A/a", "B/b"), ("B/a", "B/b"), ("A/b", "B/b"), ] for mask, offer in mismatches: assert not accept._old_match(mask, offer) def test__old_match_wildcard_matching(self): """ Wildcard matching forces the match to take place against the type or subtype of the mask and offer (depending on where the wildcard matches) """ accept = AcceptValidHeader("type/subtype") matches = [ ("*/*", "*/*"), ("*/*", "A/*"), ("*/*", "*/a"), ("*/*", "A/a"), ("A/*", "*/*"), ("A/*", "A/*"), ("A/*", "*/a"), ("A/*", "A/a"), ("*/a", "*/*"), ("*/a", "A/*"), ("*/a", "*/a"), ("*/a", "A/a"), ("A/a", "*/*"), ("A/a", "A/*"), ("A/a", "*/a"), ("A/a", "A/a"), # Offers might not contain a subtype ("*/*", "*"), ("A/*", "*"), ("*/a", "*"), ] for mask, offer in matches: assert accept._old_match(mask, offer) # Test malformed mask and offer variants where either is missing a # type or subtype assert accept._old_match("A", offer) assert accept._old_match(mask, "a") mismatches = [("B/b", "A/*"), ("B/*", "A/a"), ("B/*", "A/*"), ("*/b", "*/a")] for mask, offer in mismatches: assert not accept._old_match(mask, offer) @pytest.mark.parametrize( "header_value, returned", [ ("tExt/HtMl", True), ("APPlication/XHTML+xml", True), ("appliCATION/xMl", True), ("TeXt/XmL", True), ("image/jpg", False), ("TeXt/Plain", False), ("image/jpg, text/html", True), ], ) def test_accept_html(self, header_value, returned): instance = AcceptValidHeader(header_value=header_value) assert instance.accept_html() is returned @pytest.mark.parametrize( "header_value, returned", [ ("tExt/HtMl", True), ("APPlication/XHTML+xml", True), ("appliCATION/xMl", True), ("TeXt/XmL", True), ("image/jpg", False), ("TeXt/Plain", False), ("image/jpg, text/html", True), ], ) def test_accepts_html(self, header_value, returned): instance = AcceptValidHeader(header_value=header_value) assert instance.accepts_html is returned @pytest.mark.parametrize( "offers, expected_returned", [ (["text/html;p=1;q=0.5"], []), (["text/html;q=0.5"], []), (["text/html;q=0.5;e=1"], []), (["text/html", "text/plain;p=1;q=0.5;e=1", "foo"], [("text/html", 1.0)]), ], ) def test_acceptable_offers__invalid_offers(self, offers, expected_returned): assert ( AcceptValidHeader("text/html").acceptable_offers(offers=offers) == expected_returned ) @pytest.mark.parametrize( "header_value, offers, expected_returned", [ # RFC 7231, section 5.3.2 ( "audio/*; q=0.2, audio/basic", ["audio/mpeg", "audio/basic"], [("audio/basic", 1.0), ("audio/mpeg", 0.2)], ), ( "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c", ["text/x-dvi", "text/x-c", "text/html", "text/plain"], [ ("text/x-c", 1.0), ("text/html", 1.0), ("text/x-dvi", 0.8), ("text/plain", 0.5), ], ), ( "text/*;q=0.3, text/html;q=0.7, text/html;level=1, " + "text/html;level=2;q=0.4, */*;q=0.5", [ "text/html;level=1", "text/html", "text/plain", "image/jpeg", "text/html;level=2", "text/html;level=3", ], [ ("text/html;level=1", 1.0), ("text/html", 0.7), ("text/html;level=3", 0.7), ("image/jpeg", 0.5), ("text/html;level=2", 0.4), ("text/plain", 0.3), ], ), # Our tests ( "teXT/*;Q=0.5, TeXt/hTmL;LeVeL=1", ["tExT/HtMl;lEvEl=1", "TExt/PlAiN"], [("tExT/HtMl;lEvEl=1", 1.0), ("TExt/PlAiN", 0.5)], ), ( "text/html, application/json", ["text/html", "application/json"], [("text/html", 1.0), ("application/json", 1.0)], ), ( "text/html ;\t level=1", ["text/html\t\t ; \tlevel=1"], [("text/html\t\t ; \tlevel=1", 1.0)], ), ("", ["text/html"], []), ("text/html, image/jpeg", ["audio/basic", "text/plain"], []), ( r'text/html;p1=1;p2=2;p3="\""', [r'text/html;p1=1;p2="2";p3="\""'], [(r'text/html;p1=1;p2="2";p3="\""', 1.0)], ), ("text/html;p1=1", ["text/html;p1=2"], []), ("text/html", ["text/html;p1=1"], [("text/html;p1=1", 1.0)]), ("text/html;p1=1", ["text/html"], []), ("text/html", ["text/html"], [("text/html", 1.0)]), ("text/*", ["text/html;p=1"], [("text/html;p=1", 1.0)]), ("*/*", ["text/html;p=1"], [("text/html;p=1", 1.0)]), ("text/*", ["text/html"], [("text/html", 1.0)]), ("*/*", ["text/html"], [("text/html", 1.0)]), ("text/html;p1=1;q=0", ["text/html;p1=1"], []), ("text/html;q=0", ["text/html;p1=1", "text/html"], []), ("text/*;q=0", ["text/html;p1=1", "text/html", "text/plain"], []), ( "*/*;q=0", ["text/html;p1=1", "text/html", "text/plain", "image/jpeg"], [], ), ( "*/*;q=0, audio/mpeg", [ "text/html;p1=1", "audio/mpeg", "text/html", "text/plain", "image/jpeg", ], [("audio/mpeg", 1.0)], ), ( "text/html;p1=1, text/html;q=0", ["text/html;p1=1"], [("text/html;p1=1", 1.0)], ), ("text/html, text/*;q=0", ["text/html"], [("text/html", 1.0)]), ("text/*, */*;q=0", ["text/html"], [("text/html", 1.0)]), ("text/html;q=0, text/html", ["text/html"], []), ( "text/html", ["text/html;level=1", "text/html", "text/html;level=2"], [ ("text/html;level=1", 1.0), ("text/html", 1.0), ("text/html;level=2", 1.0), ], ), ( "text/*;q=0.3, text/html;q=0, image/png, text/html;level=1, " + "text/html;level=2;q=0.4, image/jpeg;q=0.5", [ "text/html;level=1", "text/html", "text/plain", "image/jpeg", "text/html;level=2", "text/html;level=3", "audio/basic", ], [ ("text/html;level=1", 1.0), ("image/jpeg", 0.5), ("text/html;level=2", 0.4), ("text/plain", 0.3), ], ), ( "text/*;q=0.3, text/html;q=0.5, text/html;level=1;q=0.7", ["text/*", "*/*", "text/html", "image/*"], [("text/html", 0.5)], ), ( "text/html;level=1;q=0.7", ["text/*", "*/*", "text/html", "text/html;level=1", "image/*"], [("text/html;level=1", 0.7)], ), ("*/*", ["text/*"], []), ("", ["text/*", "*/*", "text/html", "text/html;level=1", "image/*"], []), ], ) def test_acceptable_offers__valid_offers( self, header_value, offers, expected_returned ): instance = AcceptValidHeader(header_value=header_value) returned = instance.acceptable_offers(offers=offers) assert returned == expected_returned def test_acceptable_offers_uses_AcceptOffer_objects(self): from webob.acceptparse import AcceptOffer offer = AcceptOffer("text", "html", (("level", "1"),)) instance = AcceptValidHeader(header_value="text/*;q=0.5") result = instance.acceptable_offers([offer]) assert result == [(offer, 0.5)] @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptValidHeader("text/html, foo/bar") assert accept.best_match(["text/html", "foo/bar"]) == "text/html" assert accept.best_match(["foo/bar", "text/html"]) == "foo/bar" assert accept.best_match([("foo/bar", 0.5), "text/html"]) == "text/html" assert accept.best_match([("foo/bar", 0.5), ("text/html", 0.4)]) == "foo/bar" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_with_one_lower_q(self): accept = AcceptValidHeader("text/html, foo/bar;q=0.5") assert accept.best_match(["text/html", "foo/bar"]) == "text/html" accept = AcceptValidHeader("text/html;q=0.5, foo/bar") assert accept.best_match(["text/html", "foo/bar"]) == "foo/bar" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_with_complex_q(self): accept = AcceptValidHeader("text/html, foo/bar;q=0.55, baz/gort;q=0.59") assert accept.best_match(["text/html", "foo/bar"]) == "text/html" accept = AcceptValidHeader("text/html;q=0.5, foo/bar;q=0.586, baz/gort;q=0.596") assert accept.best_match(["text/html", "baz/gort"]) == "baz/gort" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_json(self): accept = AcceptValidHeader("text/html, */*; q=0.2") assert accept.best_match(["application/json"]) == "application/json" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_mixedcase(self): accept = AcceptValidHeader( "image/jpg; q=0.2, Image/pNg; Q=0.4, image/*; q=0.05" ) assert accept.best_match(["Image/JpG"]) == "Image/JpG" assert accept.best_match(["image/Tiff"]) == "image/Tiff" assert ( accept.best_match(["image/Tiff", "image/PnG", "image/jpg"]) == "image/PnG" ) @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test_best_match_zero_quality(self): assert ( AcceptValidHeader("text/plain, */*;q=0").best_match(["text/html"]) is None ) assert "audio/basic" not in AcceptValidHeader("*/*;q=0") @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): accept = AcceptValidHeader("text/html") assert accept.quality("text/html") == 1 accept = AcceptValidHeader("text/html;q=0.5") assert accept.quality("text/html") == 0.5 @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality_not_found(self): accept = AcceptValidHeader("text/html") assert accept.quality("foo/bar") is None class TestAcceptNoHeader: def test_parse__inherited(self): returned = AcceptNoHeader.parse( value=( ",\t , a/b;q=1;e1;e2=v2 \t,\t\t c/d, e/f;p1=v1;q=0;e1, " + "g/h;p1=v1\t ;\t\tp2=v2;q=0.5 \t," ) ) list_of_returned = list(returned) assert list_of_returned == [ ("a/b", 1.0, [], ["e1", ("e2", "v2")]), ("c/d", 1.0, [], []), ("e/f;p1=v1", 0.0, [("p1", "v1")], ["e1"]), ("g/h;p1=v1;p2=v2", 0.5, [("p1", "v1"), ("p2", "v2")], []), ] def test___init__(self): instance = AcceptNoHeader() assert instance.header_value is None assert instance.parsed is None assert instance._parsed_nonzero is None assert isinstance(instance, Accept) def test___add___None(self): left_operand = AcceptNoHeader() result = left_operand + None assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize( "right_operand", [ ", ", [", "], (", ",), {", ": 1.0}, {", ;level=1": (1.0, ";e1=1")}, "a/b, c/d;q=1;e1;", ["a/b", "c/d;q=1;e1;"], ("a/b", "c/d;q=1;e1;"), {"a/b": 1.0, "cd": 1.0}, {"a/b": (1.0, ";e1=1"), "c/d": (1.0, ";e2=2;")}, ], ) def test___add___invalid_value(self, right_operand): left_operand = AcceptNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize("str_", [", ", "a/b, c/d;q=1;e1;"]) def test___add___other_type_with_invalid___str__(self, str_): left_operand = AcceptNoHeader() class Other: def __str__(self): return str_ right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize("value", ["", [], (), {}]) def test___add___valid_empty_value(self, value): left_operand = AcceptNoHeader() result = left_operand + value assert isinstance(result, AcceptValidHeader) assert result.header_value == "" def test___add___other_type_with_valid___str___empty(self): left_operand = AcceptNoHeader() class Other: def __str__(self): return "" result = left_operand + Other() assert isinstance(result, AcceptValidHeader) assert result.header_value == "" @pytest.mark.parametrize( "value, value_as_header", [ # str ( "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of strs ( ["a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 3-item tuples, with extension parameters ( [ ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 2-item tuples, without extension parameters ( [("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # list of a mixture of strs, 3-item tuples and 2-item tuples ( [ ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of strs ( ("a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 3-item tuples, with extension parameters ( ( ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 2-item tuples, without extension parameters ( (("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # tuple of a mixture of strs, 3-item tuples and 2-item tuples ( ( ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # dict ( {"a/b": (0.5, ";e1=1"), "c/d": 0.0, "e/f;p1=1": (1.0, ";e1=1;e2=2")}, "e/f;p1=1;q=1;e1=1;e2=2, a/b;q=0.5;e1=1, c/d;q=0", ), ], ) def test___add___valid_value(self, value, value_as_header): result = AcceptNoHeader() + value assert isinstance(result, AcceptValidHeader) assert result.header_value == value_as_header def test___add___other_type_with_valid___str___not_empty(self): class Other: def __str__(self): return "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" right_operand = Other() result = AcceptNoHeader() + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == str(right_operand) def test___add___AcceptValidHeader_header_value_empty(self): right_operand = AcceptValidHeader(header_value="") result = AcceptNoHeader() + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___add___AcceptValidHeader_header_value_not_empty(self): right_operand = AcceptValidHeader(header_value=",\t ,i/j, k/l;q=0.333,") result = AcceptNoHeader() + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value def test___add___AcceptNoHeader(self): left_operand = AcceptNoHeader() right_operand = AcceptNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptNoHeader) assert result is not left_operand assert result is not right_operand @pytest.mark.parametrize("header_value", [", ", 'a/b;p1=1;p2=2;q=0.8;e1;e2="']) def test___add___AcceptInvalidHeader(self, header_value): left_operand = AcceptNoHeader() result = left_operand + AcceptInvalidHeader(header_value=header_value) assert isinstance(result, AcceptNoHeader) assert result is not left_operand def test___bool__(self): instance = AcceptNoHeader() returned = bool(instance) assert returned is False @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): instance = AcceptNoHeader() returned = "type/subtype" in instance assert returned is True @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptNoHeader() returned = list(instance) assert returned == [] def test___radd___None(self): right_operand = AcceptNoHeader() result = None + right_operand assert isinstance(result, AcceptNoHeader) assert result is not right_operand @pytest.mark.parametrize( "left_operand", [ ", ", [", "], (", ",), {", ": 1.0}, {", ;level=1": (1.0, ";e1=1")}, "a/b, c/d;q=1;e1;", ["a/b", "c/d;q=1;e1;"], ("a/b", "c/d;q=1;e1;"), {"a/b": 1.0, "cd": 1.0}, {"a/b": (1.0, ";e1=1"), "c/d": (1.0, ";e2=2;")}, ], ) def test___radd___invalid_value(self, left_operand): right_operand = AcceptNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptNoHeader) assert result is not right_operand @pytest.mark.parametrize("str_", [", ", "a/b, c/d;q=1;e1;"]) def test___radd___other_type_with_invalid___str__(self, str_): right_operand = AcceptNoHeader() class Other: def __str__(self): return str_ result = Other() + right_operand assert isinstance(result, AcceptNoHeader) assert result is not right_operand @pytest.mark.parametrize("value", ["", [], (), {}]) def test___radd___valid_empty_value(self, value): result = value + AcceptNoHeader() assert isinstance(result, AcceptValidHeader) assert result.header_value == "" def test___radd___other_type_with_valid___str___empty(self): class Other: def __str__(self): return "" result = Other() + AcceptNoHeader() assert isinstance(result, AcceptValidHeader) assert result.header_value == "" @pytest.mark.parametrize( "value, value_as_header", [ # str ( "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of strs ( ["a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 3-item tuples, with extension parameters ( [ ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 2-item tuples, without extension parameters ( [("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # list of a mixture of strs, 3-item tuples and 2-item tuples ( [ ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of strs ( ("a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 3-item tuples, with extension parameters ( ( ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 2-item tuples, without extension parameters ( (("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # tuple of a mixture of strs, 3-item tuples and 2-item tuples ( ( ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # dict ( {"a/b": (0.5, ";e1=1"), "c/d": 0.0, "e/f;p1=1": (1.0, ";e1=1;e2=2")}, "e/f;p1=1;q=1;e1=1;e2=2, a/b;q=0.5;e1=1, c/d;q=0", ), ], ) def test___radd___valid_non_empty_value(self, value, value_as_header): result = value + AcceptNoHeader() assert isinstance(result, AcceptValidHeader) assert result.header_value == value_as_header def test___radd___other_type_with_valid___str___not_empty(self): class Other: def __str__(self): return "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" left_operand = Other() result = left_operand + AcceptNoHeader() assert isinstance(result, AcceptValidHeader) assert result.header_value == str(left_operand) def test___repr__(self): instance = AcceptNoHeader() assert repr(instance) == "" def test___str__(self): instance = AcceptNoHeader() assert str(instance) == "" def test_accept_html(self): instance = AcceptNoHeader() assert instance.accept_html() is True def test_accepts_html(self): instance = AcceptNoHeader() assert instance.accepts_html is True @pytest.mark.parametrize( "offers, expected_returned", [ (["text/html;p=1;q=0.5"], []), (["text/html;q=0.5"], []), (["text/html;q=0.5;e=1"], []), (["text/html", "text/plain;p=1;q=0.5;e=1", "foo"], [("text/html", 1.0)]), ], ) def test_acceptable_offers__invalid_offers(self, offers, expected_returned): assert AcceptNoHeader().acceptable_offers(offers=offers) == expected_returned def test_acceptable_offers__valid_offers(self): instance = AcceptNoHeader() returned = instance.acceptable_offers(offers=["a/b", "c/d", "e/f"]) assert returned == [("a/b", 1.0), ("c/d", 1.0), ("e/f", 1.0)] @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptNoHeader() assert accept.best_match(["text/html", "audio/basic"]) == "text/html" assert ( accept.best_match([("text/html", 1), ("audio/basic", 0.5)]) == "text/html" ) assert ( accept.best_match([("text/html", 0.5), ("audio/basic", 1)]) == "audio/basic" ) assert accept.best_match([("text/html", 0.5), "audio/basic"]) == "audio/basic" assert ( accept.best_match([("text/html", 0.5), "audio/basic"], default_match=True) == "audio/basic" ) assert ( accept.best_match([("text/html", 0.5), "audio/basic"], default_match=False) == "audio/basic" ) assert accept.best_match([], default_match="fallback") == "fallback" @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): instance = AcceptNoHeader() returned = instance.quality(offer="type/subtype") assert returned == 1.0 class TestAcceptInvalidHeader: def test_parse__inherited(self): returned = AcceptInvalidHeader.parse( value=( ",\t , a/b;q=1;e1;e2=v2 \t,\t\t c/d, e/f;p1=v1;q=0;e1, " + "g/h;p1=v1\t ;\t\tp2=v2;q=0.5 \t," ) ) list_of_returned = list(returned) assert list_of_returned == [ ("a/b", 1.0, [], ["e1", ("e2", "v2")]), ("c/d", 1.0, [], []), ("e/f;p1=v1", 0.0, [("p1", "v1")], ["e1"]), ("g/h;p1=v1;p2=v2", 0.5, [("p1", "v1"), ("p2", "v2")], []), ] def test___init__(self): header_value = ", " instance = AcceptInvalidHeader(header_value=header_value) assert instance.header_value == header_value assert instance.parsed is None assert instance._parsed_nonzero is None assert isinstance(instance, Accept) def test___add___None(self): left_operand = AcceptInvalidHeader(header_value=", ") result = left_operand + None assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize( "right_operand", [ ", ", [", "], (", ",), {", ": 1.0}, {", ;level=1": (1.0, ";e1=1")}, "a/b, c/d;q=1;e1;", ["a/b", "c/d;q=1;e1;"], ("a/b", "c/d;q=1;e1;"), {"a/b": 1.0, "cd": 1.0}, {"a/b": (1.0, ";e1=1"), "c/d": (1.0, ";e2=2;")}, ], ) def test___add___invalid_value(self, right_operand): left_operand = AcceptInvalidHeader(header_value="invalid header") result = left_operand + right_operand assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize("str_", [", ", "a/b, c/d;q=1;e1;"]) def test___add___other_type_with_invalid___str__(self, str_): left_operand = AcceptInvalidHeader(header_value="invalid header") class Other: def __str__(self): return str_ right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize("value", ["", [], (), {}]) def test___add___valid_empty_value(self, value): left_operand = AcceptInvalidHeader(header_value=", ") result = left_operand + value assert isinstance(result, AcceptValidHeader) assert result.header_value == "" def test___add___other_type_with_valid___str___empty(self): left_operand = AcceptInvalidHeader(header_value=", ") class Other: def __str__(self): return "" result = left_operand + Other() assert isinstance(result, AcceptValidHeader) assert result.header_value == "" @pytest.mark.parametrize( "value, value_as_header", [ # str ( "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of strs ( ["a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 3-item tuples, with extension parameters ( [ ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 2-item tuples, without extension parameters ( [("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # list of a mixture of strs, 3-item tuples and 2-item tuples ( [ ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of strs ( ("a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 3-item tuples, with extension parameters ( ( ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 2-item tuples, without extension parameters ( (("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # tuple of a mixture of strs, 3-item tuples and 2-item tuples ( ( ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # dict ( {"a/b": (0.5, ";e1=1"), "c/d": 0.0, "e/f;p1=1": (1.0, ";e1=1;e2=2")}, "e/f;p1=1;q=1;e1=1;e2=2, a/b;q=0.5;e1=1, c/d;q=0", ), ], ) def test___add___valid_value(self, value, value_as_header): result = AcceptInvalidHeader(header_value=", ") + value assert isinstance(result, AcceptValidHeader) assert result.header_value == value_as_header def test___add___other_type_with_valid___str___not_empty(self): class Other: def __str__(self): return "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" right_operand = Other() result = AcceptInvalidHeader(header_value=", ") + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == str(right_operand) def test___add___AcceptValidHeader_header_value_empty(self): left_operand = AcceptInvalidHeader(header_value=", ") right_operand = AcceptValidHeader(header_value="") result = left_operand + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___add___AcceptValidHeader_header_value_not_empty(self): left_operand = AcceptInvalidHeader(header_value=", ") right_operand = AcceptValidHeader(header_value=",\t ,i/j, k/l;q=0.333,") result = left_operand + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == right_operand.header_value def test___add___AcceptNoHeader(self): left_operand = AcceptInvalidHeader(header_value=", ") right_operand = AcceptNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptNoHeader) assert result is not right_operand @pytest.mark.parametrize("header_value", [", ", 'a/b;p1=1;p2=2;q=0.8;e1;e2="']) def test___add___AcceptInvalidHeader(self, header_value): result = AcceptInvalidHeader(header_value=", ") + AcceptInvalidHeader( header_value=header_value ) assert isinstance(result, AcceptNoHeader) def test___bool__(self): instance = AcceptInvalidHeader(header_value=", ") returned = bool(instance) assert returned is False @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): instance = AcceptInvalidHeader(header_value=", ") returned = "type/subtype" in instance assert returned is True @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptInvalidHeader(header_value=", ") returned = list(instance) assert returned == [] def test___radd___None(self): right_operand = AcceptInvalidHeader(header_value=", ") result = None + right_operand assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize( "left_operand", [ ", ", [", "], (", ",), {", ": 1.0}, {", ;level=1": (1.0, ";e1=1")}, "a/b, c/d;q=1;e1;", ["a/b", "c/d;q=1;e1;"], ("a/b", "c/d;q=1;e1;"), {"a/b": 1.0, "cd": 1.0}, {"a/b": (1.0, ";e1=1"), "c/d": (1.0, ";e2=2;")}, ], ) def test___radd___invalid_value(self, left_operand): right_operand = AcceptInvalidHeader(header_value=", ") result = left_operand + right_operand assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize("str_", [", ", "a/b, c/d;q=1;e1;"]) def test___radd___other_type_with_invalid___str__(self, str_): right_operand = AcceptInvalidHeader(header_value=", ") class Other: def __str__(self): return str_ result = Other() + right_operand assert isinstance(result, AcceptNoHeader) @pytest.mark.parametrize("value", ["", [], (), {}]) def test___radd___valid_empty_value(self, value): right_operand = AcceptInvalidHeader(header_value="invalid header") result = value + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == "" def test___radd___other_type_with_valid___str___empty(self): right_operand = AcceptInvalidHeader(header_value="invalid header") class Other: def __str__(self): return "" result = Other() + right_operand assert isinstance(result, AcceptValidHeader) assert result.header_value == "" @pytest.mark.parametrize( "value, value_as_header", [ # str ( "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of strs ( ["a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 3-item tuples, with extension parameters ( [ ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 2-item tuples, without extension parameters ( [("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # list of a mixture of strs, 3-item tuples and 2-item tuples ( [ ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of strs ( ("a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 3-item tuples, with extension parameters ( ( ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 2-item tuples, without extension parameters ( (("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # tuple of a mixture of strs, 3-item tuples and 2-item tuples ( ( ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # dict ( {"a/b": (0.5, ";e1=1"), "c/d": 0.0, "e/f;p1=1": (1.0, ";e1=1;e2=2")}, "e/f;p1=1;q=1;e1=1;e2=2, a/b;q=0.5;e1=1, c/d;q=0", ), ], ) def test___radd___valid_non_empty_value(self, value, value_as_header): result = value + AcceptInvalidHeader(header_value="invalid header") assert isinstance(result, AcceptValidHeader) assert result.header_value == value_as_header def test___radd___other_type_with_valid___str___not_empty(self): class Other: def __str__(self): return "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" left_operand = Other() result = left_operand + AcceptInvalidHeader(header_value="invalid header") assert isinstance(result, AcceptValidHeader) assert result.header_value == str(left_operand) def test___repr__(self): instance = AcceptInvalidHeader(header_value="\x00") assert repr(instance) == "" def test___str__(self): instance = AcceptInvalidHeader(header_value=", ") assert str(instance) == "" def test_accept_html(self): instance = AcceptInvalidHeader(header_value=", ") assert instance.accept_html() is True def test_accepts_html(self): instance = AcceptInvalidHeader(header_value=", ") assert instance.accepts_html is True @pytest.mark.parametrize( "offers, expected_returned", [ (["text/html;p=1;q=0.5"], []), (["text/html;q=0.5"], []), (["text/html;q=0.5;e=1"], []), (["text/html", "text/plain;p=1;q=0.5;e=1", "foo"], [("text/html", 1.0)]), ], ) def test_acceptable_offers__invalid_offers(self, offers, expected_returned): assert ( AcceptInvalidHeader(header_value=", ").acceptable_offers(offers=offers) == expected_returned ) def test_acceptable_offers__valid_offers(self): instance = AcceptInvalidHeader(header_value=", ") returned = instance.acceptable_offers(offers=["a/b", "c/d", "e/f"]) assert returned == [("a/b", 1.0), ("c/d", 1.0), ("e/f", 1.0)] @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptInvalidHeader(header_value=", ") assert accept.best_match(["text/html", "audio/basic"]) == "text/html" assert ( accept.best_match([("text/html", 1), ("audio/basic", 0.5)]) == "text/html" ) assert ( accept.best_match([("text/html", 0.5), ("audio/basic", 1)]) == "audio/basic" ) assert accept.best_match([("text/html", 0.5), "audio/basic"]) == "audio/basic" assert ( accept.best_match([("text/html", 0.5), "audio/basic"], default_match=True) == "audio/basic" ) assert ( accept.best_match([("text/html", 0.5), "audio/basic"], default_match=False) == "audio/basic" ) assert accept.best_match([], default_match="fallback") == "fallback" @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): instance = AcceptInvalidHeader(header_value=", ") returned = instance.quality(offer="type/subtype") assert returned == 1.0 class TestCreateAcceptHeader: def test_header_value_is_None(self): header_value = None returned = create_accept_header(header_value=header_value) assert isinstance(returned, AcceptNoHeader) assert returned.header_value == header_value returned2 = create_accept_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value def test_header_value_is_valid(self): header_value = "text/html, text/plain;q=0.9" returned = create_accept_header(header_value=header_value) assert isinstance(returned, AcceptValidHeader) assert returned.header_value == header_value returned2 = create_accept_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value @pytest.mark.parametrize("header_value", [", ", "noslash"]) def test_header_value_is_invalid(self, header_value): returned = create_accept_header(header_value=header_value) assert isinstance(returned, AcceptInvalidHeader) assert returned.header_value == header_value returned2 = create_accept_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value class TestAcceptProperty: def test_fget_header_is_valid(self): header_value = 'text/html;p1="1";p2=v2;q=0.9;e1="1";e2, audio/basic' request = Request.blank("/", environ={"HTTP_ACCEPT": header_value}) property_ = accept_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptValidHeader) assert returned.header_value == header_value def test_fget_header_is_None(self): request = Request.blank("/", environ={"HTTP_ACCEPT": None}) property_ = accept_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptNoHeader) def test_fget_header_is_invalid(self): header_value = "invalid" request = Request.blank("/", environ={"HTTP_ACCEPT": header_value}) property_ = accept_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptInvalidHeader) assert returned.header_value == header_value def test_fset_value_is_valid(self): request = Request.blank("/", environ={"HTTP_ACCEPT": "text/html"}) header_value = 'text/html;p1="1";p2=v2;q=0.9;e1="1";e2, audio/basic' property_ = accept_property() property_.fset(request=request, value=header_value) assert request.environ["HTTP_ACCEPT"] == header_value def test_fset_value_is_None(self): request = Request.blank("/", environ={"HTTP_ACCEPT": "text/html"}) property_ = accept_property() property_.fset(request=request, value=None) assert "HTTP_ACCEPT" not in request.environ def test_fset_value_is_invalid(self): request = Request.blank("/", environ={"HTTP_ACCEPT": "text/html"}) header_value = "invalid" property_ = accept_property() property_.fset(request=request, value=header_value) assert request.environ["HTTP_ACCEPT"] == header_value @pytest.mark.parametrize( "value, value_as_header", [ ("", ""), ([], ""), ((), ""), ({}, ""), # str ( "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of strs ( ["a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 3-item tuples, with extension parameters ( [ ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # list of 2-item tuples, without extension parameters ( [("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # list of a mixture of strs, 3-item tuples and 2-item tuples ( [ ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ], "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of strs ( ("a/b;q=0.5", "c/d;p1=1;q=0", "e/f", "g/h;p1=1;q=1;e1=1"), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 3-item tuples, with extension parameters ( ( ("a/b", 0.5, ""), ("c/d;p1=1", 0.0, ""), ("e/f", 1.0, ""), ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # tuple of 2-item tuples, without extension parameters ( (("a/b", 0.5), ("c/d;p1=1", 0.0), ("e/f", 1.0), ("g/h;p1=1", 1.0)), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1", ), # tuple of a mixture of strs, 3-item tuples and 2-item tuples ( ( ("a/b", 0.5), ("c/d;p1=1", 0.0, ""), "e/f", ("g/h;p1=1", 1.0, ";e1=1"), ), "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1", ), # dict ( {"a/b": (0.5, ";e1=1"), "c/d": 0.0, "e/f;p1=1": (1.0, ";e1=1;e2=2")}, "e/f;p1=1;q=1;e1=1;e2=2, a/b;q=0.5;e1=1, c/d;q=0", ), ], ) def test_fset_value_types(self, value, value_as_header): request = Request.blank("/", environ={"HTTP_ACCEPT": "text/html"}) property_ = accept_property() property_.fset(request=request, value=value) assert request.environ["HTTP_ACCEPT"] == value_as_header @pytest.mark.parametrize( "header_value", ["", "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1"] ) def test_fset_other_type_with___str__(self, header_value): request = Request.blank("/", environ={"HTTP_ACCEPT": "text/html"}) property_ = accept_property() class Other: def __str__(self): return header_value value = Other() property_.fset(request=request, value=value) assert request.environ["HTTP_ACCEPT"] == str(value) def test_fset_AcceptValidHeader(self): request = Request.blank("/", environ={}) header_value = "a/b;q=0.5, c/d;p1=1;q=0, e/f, g/h;p1=1;q=1;e1=1" header = AcceptValidHeader(header_value=header_value) property_ = accept_property() property_.fset(request=request, value=header) assert request.environ["HTTP_ACCEPT"] == header.header_value def test_fset_AcceptNoHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT": "text/html"}) property_ = accept_property() header = AcceptNoHeader() property_.fset(request=request, value=header) assert "HTTP_ACCEPT" not in request.environ def test_fset_AcceptInvalidHeader(self): request = Request.blank("/", environ={}) header_value = "invalid" header = AcceptInvalidHeader(header_value=header_value) property_ = accept_property() property_.fset(request=request, value=header) assert request.environ["HTTP_ACCEPT"] == header.header_value def test_fdel_header_key_in_environ(self): request = Request.blank("/", environ={"HTTP_ACCEPT": "text/html"}) property_ = accept_property() property_.fdel(request=request) assert "HTTP_ACCEPT" not in request.environ def test_fdel_header_key_not_in_environ(self): request = Request.blank("/") property_ = accept_property() property_.fdel(request=request) assert "HTTP_ACCEPT" not in request.environ class TestAcceptCharset: @pytest.mark.parametrize( "value", [ "", '"', "(", ")", "/", ":", ";", "<", "=", ">", "?", "@", "[", "\\", "]", "{", "}", "foo, bar, baz;q= 0.001", "foo , ,bar,charlie ", ], ) def test_parse__invalid_header(self, value): with pytest.raises(ValueError): AcceptCharset.parse(value=value) @pytest.mark.parametrize( "value, expected_list", [ ("*", [("*", 1.0)]), ("!#$%&'*+-.^_`|~;q=0.5", [("!#$%&'*+-.^_`|~", 0.5)]), ("0123456789", [("0123456789", 1.0)]), ( ",\t foo \t;\t q=0.345,, bar ; Q=0.456 \t, ,\tcharlie \t,, ,", [("foo", 0.345), ("bar", 0.456), ("charlie", 1.0)], ), ( "iso-8859-5;q=0.372,unicode-1-1;q=0.977,UTF-8, *;q=0.000", [ ("iso-8859-5", 0.372), ("unicode-1-1", 0.977), ("UTF-8", 1.0), ("*", 0.0), ], ), # RFC 7230 Section 7 ("foo,bar", [("foo", 1.0), ("bar", 1.0)]), ("foo, bar,", [("foo", 1.0), ("bar", 1.0)]), # RFC 7230 Errata ID: 4169 ("foo , ,bar,charlie", [("foo", 1.0), ("bar", 1.0), ("charlie", 1.0)]), ], ) def test_parse__valid_header(self, value, expected_list): returned = AcceptCharset.parse(value=value) list_of_returned = list(returned) assert list_of_returned == expected_list class TestAcceptCharsetValidHeader: def test_parse__inherited(self): returned = AcceptCharsetValidHeader.parse( value=",iso-8859-5 ; q=0.333 , ,utf-8,unicode-1-1 ;q=0.90," ) list_of_returned = list(returned) assert list_of_returned == [ ("iso-8859-5", 0.333), ("utf-8", 1.0), ("unicode-1-1", 0.9), ] @pytest.mark.parametrize("header_value", ["", ", iso-8859-5 "]) def test___init___invalid_header(self, header_value): with pytest.raises(ValueError): AcceptCharsetValidHeader(header_value=header_value) def test___init___valid_header(self): header_value = "iso-8859-5;q=0.372,unicode-1-1;q=0.977,UTF-8, *;q=0.000" instance = AcceptCharsetValidHeader(header_value=header_value) assert instance.header_value == header_value assert instance.parsed == [ ("iso-8859-5", 0.372), ("unicode-1-1", 0.977), ("UTF-8", 1.0), ("*", 0.0), ] assert instance._parsed_nonzero == [ ("iso-8859-5", 0.372), ("unicode-1-1", 0.977), ("UTF-8", 1.0), ] assert isinstance(instance, AcceptCharset) def test___add___None(self): left_operand = AcceptCharsetValidHeader(header_value="iso-8859-5") result = left_operand + None assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize( "right_operand", ["", [], (), {}, "UTF/8", ["UTF/8"], ("UTF/8",), {"UTF/8": 1.0}], ) def test___add___invalid_value(self, right_operand): left_operand = AcceptCharsetValidHeader(header_value="iso-8859-5") result = left_operand + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize("str_", ["", "UTF/8"]) def test___add___other_type_with_invalid___str__(self, str_): left_operand = AcceptCharsetValidHeader(header_value="iso-8859-5") class Other: def __str__(self): return str_ right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize( "value, value_as_header", [ ( "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( [("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"], "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( (("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"), "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( {"UTF-7": 0.5, "unicode-1-1": 0.0, "UTF-8": 1.0}, "UTF-8, UTF-7;q=0.5, unicode-1-1;q=0", ), ], ) def test___add___valid_value(self, value, value_as_header): left_operand = AcceptCharsetValidHeader(header_value=",\t ,iso-8859-5;q=0.333,") result = left_operand + value assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == left_operand.header_value + ", " + value_as_header def test___add___other_type_with_valid___str__(self): left_operand = AcceptCharsetValidHeader(header_value=",\t ,iso-8859-5;q=0.333,") class Other: def __str__(self): return "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8" right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == left_operand.header_value + ", " + str( right_operand ) def test___add___AcceptCharsetValidHeader(self): left_operand = AcceptCharsetValidHeader(header_value=",\t ,iso-8859-5;q=0.333,") right_operand = AcceptCharsetValidHeader( header_value=", ,utf-7;q=0, \tutf-8;q=1," ) result = left_operand + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert ( result.header_value == left_operand.header_value + ", " + right_operand.header_value ) def test___add___AcceptCharsetNoHeader(self): valid_header_instance = AcceptCharsetValidHeader( header_value=", ,utf-7;q=0, \tutf-8;q=1," ) result = valid_header_instance + AcceptCharsetNoHeader() assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == valid_header_instance.header_value assert result is not valid_header_instance @pytest.mark.parametrize("header_value", ["", "utf/8"]) def test___add___AcceptCharsetInvalidHeader(self, header_value): valid_header_instance = AcceptCharsetValidHeader(header_value="header") result = valid_header_instance + AcceptCharsetInvalidHeader( header_value=header_value ) assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == valid_header_instance.header_value assert result is not valid_header_instance def test___bool__(self): instance = AcceptCharsetValidHeader(header_value="valid-header") returned = bool(instance) assert returned is True @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): for mask in ["*", "utf-8", "UTF-8"]: assert "utf-8" in AcceptCharsetValidHeader(mask) assert "utf-8" not in AcceptCharsetValidHeader("utf-7") @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains___not(self): accept = AcceptCharsetValidHeader("utf-8") assert "utf-7" not in accept @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains___zero_quality(self): assert "foo" not in AcceptCharsetValidHeader("*;q=0") @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptCharsetValidHeader( header_value="utf-8; q=0.5, utf-7; q=0, iso-8859-5; q=0.8, unicode-1-1" ) assert list(instance) == ["unicode-1-1", "iso-8859-5", "utf-8"] def test___radd___None(self): right_operand = AcceptCharsetValidHeader(header_value="iso-8859-5") result = None + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize( "left_operand", ["", [], (), {}, "UTF/8", ["UTF/8"], ("UTF/8",), {"UTF/8": 1.0}] ) def test___radd___invalid_value(self, left_operand): right_operand = AcceptCharsetValidHeader(header_value="iso-8859-5") result = left_operand + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize("str_", ["", "UTF/8"]) def test___radd___other_type_with_invalid___str__(self, str_): right_operand = AcceptCharsetValidHeader(header_value="iso-8859-5") class Other: def __str__(self): return str_ result = Other() + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize( "value, value_as_header", [ ( "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( [("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"], "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( (("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"), "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( {"UTF-7": 0.5, "unicode-1-1": 0.0, "UTF-8": 1.0}, "UTF-8, UTF-7;q=0.5, unicode-1-1;q=0", ), ], ) def test___radd___valid_value(self, value, value_as_header): right_operand = AcceptCharsetValidHeader( header_value=",\t ,iso-8859-5;q=0.333," ) result = value + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert ( result.header_value == value_as_header + ", " + right_operand.header_value ) def test___radd___other_type_with_valid___str__(self): right_operand = AcceptCharsetValidHeader( header_value=",\t ,iso-8859-5;q=0.333," ) class Other: def __str__(self): return "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8" left_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert ( result.header_value == str(left_operand) + ", " + right_operand.header_value ) def test___repr__(self): instance = AcceptCharsetValidHeader(header_value=",utf-7;q=0.200,UTF-8;q=0.300") assert ( repr(instance) == "" ) def test___str__(self): header_value = ( ", \t,iso-8859-5;q=0.000 \t, utf-8;q=1.000, UTF-7, " "unicode-1-1;q=0.210 ," ) instance = AcceptCharsetValidHeader(header_value=header_value) assert str(instance) == "iso-8859-5;q=0, utf-8, UTF-7, unicode-1-1;q=0.21" @pytest.mark.parametrize( "header_value, offers, returned", [ ("UTF-7, unicode-1-1", ["UTF-8", "iso-8859-5"], []), ( "utf-8, unicode-1-1, iSo-8859-5", ["UTF-8", "iso-8859-5"], [("UTF-8", 1.0), ("iso-8859-5", 1.0)], ), ( "utF-8;q=0.2, uniCode-1-1;q=0.9, iSo-8859-5;q=0.8", ["iso-8859-5", "unicode-1-1", "utf-8"], [("unicode-1-1", 0.9), ("iso-8859-5", 0.8), ("utf-8", 0.2)], ), ( "utf-8, unicode-1-1;q=0.9, iSo-8859-5;q=0.9", ["iso-8859-5", "utf-8", "unicode-1-1"], [("utf-8", 1.0), ("iso-8859-5", 0.9), ("unicode-1-1", 0.9)], ), ("*", ["UTF-8", "iso-8859-5"], [("UTF-8", 1.0), ("iso-8859-5", 1.0)]), ("*;q=0.8", ["UTF-8", "iso-8859-5"], [("UTF-8", 0.8), ("iso-8859-5", 0.8)]), ("UTF-7, *", ["UTF-8", "UTF-7"], [("UTF-8", 1.0), ("UTF-7", 1.0)]), ("UTF-7;q=0.5, *", ["UTF-7", "UTF-8"], [("UTF-8", 1.0), ("UTF-7", 0.5)]), ("UTF-8, *;q=0", ["UTF-7"], []), ("UTF-8, *;q=0", ["UTF-8"], [("UTF-8", 1.0)]), ("UTF-8;q=0, *", ["UTF-8"], []), ("UTF-8;q=0, *;q=0", ["UTF-8", "UTF-7"], []), ("UTF-8, UTF-8;q=0", ["UTF-8"], [("UTF-8", 1.0)]), ( "UTF-8, UTF-8;q=0, UTF-7", ["UTF-8", "UTF-7"], [("UTF-8", 1.0), ("UTF-7", 1.0)], ), ( "UTF-8;q=0.5, UTF-8;q=0.7, UTF-8;q=0.6, UTF-7", ["UTF-8", "UTF-7"], [("UTF-7", 1.0), ("UTF-8", 0.5)], ), ( "UTF-8;q=0.8, *;q=0.9, *;q=0", ["UTF-8", "UTF-7"], [("UTF-7", 0.9), ("UTF-8", 0.8)], ), ("UTF-8;q=0.8, *;q=0, *;q=0.9", ["UTF-8", "UTF-7"], [("UTF-8", 0.8)]), ], ) def test_acceptable_offers(self, header_value, offers, returned): instance = AcceptCharsetValidHeader(header_value=header_value) assert instance.acceptable_offers(offers=offers) == returned @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptCharsetValidHeader("utf-8, iso-8859-5") assert accept.best_match(["utf-8", "iso-8859-5"]) == "utf-8" assert accept.best_match(["iso-8859-5", "utf-8"]) == "iso-8859-5" assert accept.best_match([("iso-8859-5", 0.5), "utf-8"]) == "utf-8" assert accept.best_match([("iso-8859-5", 0.5), ("utf-8", 0.4)]) == "iso-8859-5" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_with_one_lower_q(self): accept = AcceptCharsetValidHeader("utf-8, iso-8859-5;q=0.5") assert accept.best_match(["utf-8", "iso-8859-5"]) == "utf-8" accept = AcceptCharsetValidHeader("utf-8;q=0.5, iso-8859-5") assert accept.best_match(["utf-8", "iso-8859-5"]) == "iso-8859-5" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_with_complex_q(self): accept = AcceptCharsetValidHeader("utf-8, iso-8859-5;q=0.55, utf-7;q=0.59") assert accept.best_match(["utf-8", "iso-8859-5"]) == "utf-8" accept = AcceptCharsetValidHeader( "utf-8;q=0.5, iso-8859-5;q=0.586, utf-7;q=0.596" ) assert accept.best_match(["utf-8", "utf-7"]) == "utf-7" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_mixedcase(self): accept = AcceptCharsetValidHeader("uTf-8; q=0.2, UtF-7; Q=0.4, *; q=0.05") assert accept.best_match(["UtF-8"]) == "UtF-8" assert accept.best_match(["IsO-8859-5"]) == "IsO-8859-5" assert accept.best_match(["iSo-8859-5", "uTF-7", "UtF-8"]) == "uTF-7" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test_best_match_zero_quality(self): assert AcceptCharsetValidHeader("utf-7, *;q=0").best_match(["utf-8"]) is None assert "char-set" not in AcceptCharsetValidHeader("*;q=0") @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): accept = AcceptCharsetValidHeader("utf-8") assert accept.quality("utf-8") == 1.0 accept = AcceptCharsetValidHeader("utf-8;q=0.5") assert accept.quality("utf-8") == 0.5 @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality_not_found(self): accept = AcceptCharsetValidHeader("utf-8") assert accept.quality("iso-8859-5") is None class TestAcceptCharsetNoHeader: def test_parse__inherited(self): returned = AcceptCharsetNoHeader.parse( value=",iso-8859-5 ; q=0.333 , ,utf-8,unicode-1-1 ;q=0.90," ) list_of_returned = list(returned) assert list_of_returned == [ ("iso-8859-5", 0.333), ("utf-8", 1.0), ("unicode-1-1", 0.9), ] def test___init__(self): instance = AcceptCharsetNoHeader() assert instance.header_value is None assert instance.parsed is None assert instance._parsed_nonzero is None assert isinstance(instance, AcceptCharset) def test___add___None(self): instance = AcceptCharsetNoHeader() result = instance + None assert isinstance(result, AcceptCharsetNoHeader) assert result is not instance @pytest.mark.parametrize( "right_operand", ["", [], (), {}, "UTF/8", ["UTF/8"], ("UTF/8",), {"UTF/8": 1.0}], ) def test___add___invalid_value(self, right_operand): left_operand = AcceptCharsetNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptCharsetNoHeader) assert result is not left_operand @pytest.mark.parametrize("str_", ["", "UTF/8"]) def test___add___other_type_with_invalid___str__(self, str_): left_operand = AcceptCharsetNoHeader() class Other: def __str__(self): return str_ result = left_operand + Other() assert isinstance(result, AcceptCharsetNoHeader) assert result is not left_operand @pytest.mark.parametrize( "value, value_as_header", [ ( "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( [("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"], "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( (("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"), "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( {"UTF-7": 0.5, "unicode-1-1": 0.0, "UTF-8": 1.0}, "UTF-8, UTF-7;q=0.5, unicode-1-1;q=0", ), ], ) def test___add___valid_value(self, value, value_as_header): result = AcceptCharsetNoHeader() + value assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == value_as_header def test___add___other_type_with_valid___str__(self): class Other: def __str__(self): return "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8" right_operand = Other() result = AcceptCharsetNoHeader() + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == str(right_operand) def test___add___AcceptCharsetValidHeader(self): right_operand = AcceptCharsetValidHeader( header_value=", ,utf-7;q=0, \tutf-8;q=1," ) result = AcceptCharsetNoHeader() + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___add___AcceptCharsetNoHeader(self): left_operand = AcceptCharsetNoHeader() right_operand = AcceptCharsetNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptCharsetNoHeader) assert result is not left_operand assert result is not right_operand @pytest.mark.parametrize("header_value", ["", "utf/8"]) def test___add___AcceptCharsetInvalidHeader(self, header_value): left_operand = AcceptCharsetNoHeader() result = left_operand + AcceptCharsetInvalidHeader(header_value=header_value) assert isinstance(result, AcceptCharsetNoHeader) assert result is not left_operand def test___bool__(self): instance = AcceptCharsetNoHeader() returned = bool(instance) assert returned is False @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): instance = AcceptCharsetNoHeader() returned = "char-set" in instance assert returned is True @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptCharsetNoHeader() returned = list(instance) assert returned == [] def test___radd___None(self): right_operand = AcceptCharsetNoHeader() result = None + right_operand assert isinstance(result, AcceptCharsetNoHeader) assert result is not right_operand @pytest.mark.parametrize( "left_operand", ["", [], (), {}, "UTF/8", ["UTF/8"], ("UTF/8",), {"UTF/8": 1.0}] ) def test___radd___invalid_value(self, left_operand): right_operand = AcceptCharsetNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptCharsetNoHeader) assert result is not right_operand @pytest.mark.parametrize("str_", ["", "UTF/8"]) def test___radd___other_type_with_invalid___str__(self, str_): right_operand = AcceptCharsetNoHeader() class Other: def __str__(self): return str_ result = Other() + right_operand assert isinstance(result, AcceptCharsetNoHeader) assert result is not right_operand @pytest.mark.parametrize( "value, value_as_header", [ ( "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( [("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"], "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( (("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"), "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( {"UTF-7": 0.5, "unicode-1-1": 0.0, "UTF-8": 1.0}, "UTF-8, UTF-7;q=0.5, unicode-1-1;q=0", ), ], ) def test___radd___valid_value(self, value, value_as_header): result = value + AcceptCharsetNoHeader() assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == value_as_header def test___radd___other_type_with_valid___str__(self): class Other: def __str__(self): return "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8" left_operand = Other() result = left_operand + AcceptCharsetNoHeader() assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == str(left_operand) def test___repr__(self): instance = AcceptCharsetNoHeader() assert repr(instance) == "" def test___str__(self): instance = AcceptCharsetNoHeader() assert str(instance) == "" def test_acceptable_offers(self): instance = AcceptCharsetNoHeader() returned = instance.acceptable_offers(offers=["utf-8", "utf-7", "unicode-1-1"]) assert returned == [("utf-8", 1.0), ("utf-7", 1.0), ("unicode-1-1", 1.0)] @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptCharsetNoHeader() assert accept.best_match(["utf-8", "iso-8859-5"]) == "utf-8" assert accept.best_match([("utf-8", 1), ("iso-8859-5", 0.5)]) == "utf-8" assert accept.best_match([("utf-8", 0.5), ("iso-8859-5", 1)]) == "iso-8859-5" assert accept.best_match([("utf-8", 0.5), "iso-8859-5"]) == "iso-8859-5" assert ( accept.best_match([("utf-8", 0.5), "iso-8859-5"], default_match=True) == "iso-8859-5" ) assert ( accept.best_match([("utf-8", 0.5), "iso-8859-5"], default_match=False) == "iso-8859-5" ) assert accept.best_match([], default_match="fallback") == "fallback" @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): instance = AcceptCharsetNoHeader() returned = instance.quality(offer="char-set") assert returned == 1.0 class TestAcceptCharsetInvalidHeader: def test_parse__inherited(self): returned = AcceptCharsetInvalidHeader.parse( value=",iso-8859-5 ; q=0.333 , ,utf-8,unicode-1-1 ;q=0.90," ) list_of_returned = list(returned) assert list_of_returned == [ ("iso-8859-5", 0.333), ("utf-8", 1.0), ("unicode-1-1", 0.9), ] def test___init__(self): header_value = "invalid header" instance = AcceptCharsetInvalidHeader(header_value=header_value) assert instance.header_value == header_value assert instance.parsed is None assert instance._parsed_nonzero is None assert isinstance(instance, AcceptCharset) def test___add___None(self): instance = AcceptCharsetInvalidHeader(header_value="") result = instance + None assert isinstance(result, AcceptCharsetNoHeader) @pytest.mark.parametrize( "right_operand", ["", [], (), {}, "UTF/8", ["UTF/8"], ("UTF/8",), {"UTF/8": 1.0}], ) def test___add___invalid_value(self, right_operand): result = AcceptCharsetInvalidHeader(header_value="") + right_operand assert isinstance(result, AcceptCharsetNoHeader) @pytest.mark.parametrize("str_", ["", "UTF/8"]) def test___add___other_type_with_invalid___str__(self, str_): class Other: def __str__(self): return str_ result = AcceptCharsetInvalidHeader(header_value="") + Other() assert isinstance(result, AcceptCharsetNoHeader) @pytest.mark.parametrize( "value, value_as_header", [ ( "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( [("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"], "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( (("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"), "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( {"UTF-7": 0.5, "unicode-1-1": 0.0, "UTF-8": 1.0}, "UTF-8, UTF-7;q=0.5, unicode-1-1;q=0", ), ], ) def test___add___valid_header_value(self, value, value_as_header): result = AcceptCharsetInvalidHeader(header_value="") + value assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == value_as_header def test___add___other_type_valid_header_value(self): class Other: def __str__(self): return "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8" right_operand = Other() result = AcceptCharsetInvalidHeader(header_value="") + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == str(right_operand) def test___add___AcceptCharsetValidHeader(self): right_operand = AcceptCharsetValidHeader( header_value=", ,utf-7;q=0, \tutf-8;q=1," ) result = AcceptCharsetInvalidHeader(header_value="") + right_operand assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___add___AcceptCharsetNoHeader(self): right_operand = AcceptCharsetNoHeader() result = AcceptCharsetInvalidHeader(header_value="") + right_operand assert isinstance(result, AcceptCharsetNoHeader) assert result is not right_operand def test___add___AcceptCharsetInvalidHeader(self): result = AcceptCharsetInvalidHeader( header_value="" ) + AcceptCharsetInvalidHeader(header_value="utf/8") assert isinstance(result, AcceptCharsetNoHeader) def test___bool__(self): instance = AcceptCharsetInvalidHeader(header_value="") returned = bool(instance) assert returned is False @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): instance = AcceptCharsetInvalidHeader(header_value="") returned = "char-set" in instance assert returned is True @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptCharsetInvalidHeader(header_value="") returned = list(instance) assert returned == [] def test___radd___None(self): result = None + AcceptCharsetInvalidHeader(header_value="") assert isinstance(result, AcceptCharsetNoHeader) @pytest.mark.parametrize( "left_operand", ["", [], (), {}, "UTF/8", ["UTF/8"], ("UTF/8",), {"UTF/8": 1.0}] ) def test___radd___invalid_value(self, left_operand): result = left_operand + AcceptCharsetInvalidHeader(header_value="") assert isinstance(result, AcceptCharsetNoHeader) @pytest.mark.parametrize("str_", ["", "UTF/8"]) def test___radd___other_type_with_invalid___str__(self, str_): class Other: def __str__(self): return str_ result = Other() + AcceptCharsetInvalidHeader(header_value="") assert isinstance(result, AcceptCharsetNoHeader) @pytest.mark.parametrize( "value, value_as_header", [ ( "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( [("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"], "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( (("UTF-7", 0.5), ("unicode-1-1", 0.0), "UTF-8"), "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8", ), ( {"UTF-7": 0.5, "unicode-1-1": 0.0, "UTF-8": 1.0}, "UTF-8, UTF-7;q=0.5, unicode-1-1;q=0", ), ], ) def test___radd___valid_header_value(self, value, value_as_header): result = value + AcceptCharsetInvalidHeader(header_value="") assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == value_as_header def test___radd___other_type_valid_header_value(self): class Other: def __str__(self): return "UTF-7;q=0.5, unicode-1-1;q=0, UTF-8" left_operand = Other() result = left_operand + AcceptCharsetInvalidHeader(header_value="") assert isinstance(result, AcceptCharsetValidHeader) assert result.header_value == str(left_operand) def test___repr__(self): instance = AcceptCharsetInvalidHeader(header_value="\x00") assert repr(instance) == "" def test___str__(self): instance = AcceptCharsetInvalidHeader(header_value="") assert str(instance) == "" def test_acceptable_offers(self): instance = AcceptCharsetInvalidHeader(header_value="") returned = instance.acceptable_offers(offers=["utf-8", "utf-7", "unicode-1-1"]) assert returned == [("utf-8", 1.0), ("utf-7", 1.0), ("unicode-1-1", 1.0)] @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptCharsetInvalidHeader(header_value="") assert accept.best_match(["utf-8", "iso-8859-5"]) == "utf-8" assert accept.best_match([("utf-8", 1), ("iso-8859-5", 0.5)]) == "utf-8" assert accept.best_match([("utf-8", 0.5), ("iso-8859-5", 1)]) == "iso-8859-5" assert accept.best_match([("utf-8", 0.5), "iso-8859-5"]) == "iso-8859-5" assert ( accept.best_match([("utf-8", 0.5), "iso-8859-5"], default_match=True) == "iso-8859-5" ) assert ( accept.best_match([("utf-8", 0.5), "iso-8859-5"], default_match=False) == "iso-8859-5" ) assert accept.best_match([], default_match="fallback") == "fallback" @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): instance = AcceptCharsetInvalidHeader(header_value="") returned = instance.quality(offer="char-set") assert returned == 1.0 class TestCreateAcceptCharsetHeader: def test_header_value_is_valid(self): header_value = "iso-8859-5, unicode-1-1;q=0.8" returned = create_accept_charset_header(header_value=header_value) assert isinstance(returned, AcceptCharsetValidHeader) assert returned.header_value == header_value returned2 = create_accept_charset_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value def test_header_value_is_None(self): header_value = None returned = create_accept_charset_header(header_value=header_value) assert isinstance(returned, AcceptCharsetNoHeader) assert returned.header_value == header_value returned2 = create_accept_charset_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value @pytest.mark.parametrize("header_value", ["", "iso-8859-5, unicode/1"]) def test_header_value_is_invalid(self, header_value): returned = create_accept_charset_header(header_value=header_value) assert isinstance(returned, AcceptCharsetInvalidHeader) assert returned.header_value == header_value returned2 = create_accept_charset_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value class TestAcceptCharsetProperty: def test_fget_header_is_None(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": None}) property_ = accept_charset_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptCharsetNoHeader) def test_fget_header_is_valid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": "UTF-8"}) property_ = accept_charset_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptCharsetValidHeader) def test_fget_header_is_invalid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": ""}) property_ = accept_charset_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptCharsetInvalidHeader) def test_fset_value_is_None(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": "UTF-8"}) property_ = accept_charset_property() property_.fset(request=request, value=None) assert isinstance(request.accept_charset, AcceptCharsetNoHeader) assert "HTTP_ACCEPT_CHARSET" not in request.environ def test_fset_value_is_invalid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": "UTF-8"}) property_ = accept_charset_property() property_.fset(request=request, value="") assert isinstance(request.accept_charset, AcceptCharsetInvalidHeader) assert request.environ["HTTP_ACCEPT_CHARSET"] == "" def test_fset_value_is_valid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": "UTF-8"}) property_ = accept_charset_property() property_.fset(request=request, value="UTF-7") assert isinstance(request.accept_charset, AcceptCharsetValidHeader) assert request.environ["HTTP_ACCEPT_CHARSET"] == "UTF-7" @pytest.mark.parametrize( "value, value_as_header", [ ( "utf-8;q=0.5, iso-8859-5;q=0, utf-7", "utf-8;q=0.5, iso-8859-5;q=0, utf-7", ), ( [("utf-8", 0.5), ("iso-8859-5", 0.0), "utf-7"], "utf-8;q=0.5, iso-8859-5;q=0, utf-7", ), ( (("utf-8", 0.5), ("iso-8859-5", 0.0), "utf-7"), "utf-8;q=0.5, iso-8859-5;q=0, utf-7", ), ( {"utf-8": 0.5, "iso-8859-5": 0.0, "utf-7": 1.0}, "utf-7, utf-8;q=0.5, iso-8859-5;q=0", ), ], ) def test_fset_value_types(self, value, value_as_header): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": ""}) property_ = accept_charset_property() property_.fset(request=request, value=value) assert isinstance(request.accept_charset, AcceptCharsetValidHeader) assert request.environ["HTTP_ACCEPT_CHARSET"] == value_as_header def test_fset_other_type_with_valid___str__(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": ""}) property_ = accept_charset_property() class Other: def __str__(self): return "utf-8;q=0.5, iso-8859-5;q=0, utf-7" value = Other() property_.fset(request=request, value=value) assert isinstance(request.accept_charset, AcceptCharsetValidHeader) assert request.environ["HTTP_ACCEPT_CHARSET"] == str(value) def test_fset_AcceptCharsetNoHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": "utf-8"}) property_ = accept_charset_property() header = AcceptCharsetNoHeader() property_.fset(request=request, value=header) assert isinstance(request.accept_charset, AcceptCharsetNoHeader) assert "HTTP_ACCEPT_CHARSET" not in request.environ def test_fset_AcceptCharsetValidHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": "utf-8"}) property_ = accept_charset_property() header = AcceptCharsetValidHeader("utf-7") property_.fset(request=request, value=header) assert isinstance(request.accept_charset, AcceptCharsetValidHeader) assert request.environ["HTTP_ACCEPT_CHARSET"] == header.header_value def test_fset_AcceptCharsetInvalidHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": "utf-8"}) property_ = accept_charset_property() header = AcceptCharsetInvalidHeader("") property_.fset(request=request, value=header) assert isinstance(request.accept_charset, AcceptCharsetInvalidHeader) assert request.environ["HTTP_ACCEPT_CHARSET"] == header.header_value def test_fdel_header_key_in_environ(self): request = Request.blank("/", environ={"HTTP_ACCEPT_CHARSET": "utf-8"}) property_ = accept_charset_property() property_.fdel(request=request) assert isinstance(request.accept_charset, AcceptCharsetNoHeader) assert "HTTP_ACCEPT_CHARSET" not in request.environ def test_fdel_header_key_not_in_environ(self): request = Request.blank("/") property_ = accept_charset_property() property_.fdel(request=request) assert isinstance(request.accept_charset, AcceptCharsetNoHeader) assert "HTTP_ACCEPT_CHARSET" not in request.environ class TestAcceptEncoding: @pytest.mark.parametrize( "value", [ '"', "(", ")", "/", ":", ";", "<", "=", ">", "?", "@", "[", "\\", "]", "{", "}", ", ", ", , ", "gzip;q=1.0, identity; q =0.5, *;q=0", ], ) def test_parse__invalid_header(self, value): with pytest.raises(ValueError): AcceptEncoding.parse(value=value) @pytest.mark.parametrize( "value, expected_list", [ (",", []), (", ,", []), ("*", [("*", 1.0)]), ("!#$%&'*+-.^_`|~;q=0.5", [("!#$%&'*+-.^_`|~", 0.5)]), ("0123456789", [("0123456789", 1.0)]), ( ",,\t foo \t;\t q=0.345,, bar ; Q=0.456 \t, ,\tCHARLIE \t,, ,", [("foo", 0.345), ("bar", 0.456), ("CHARLIE", 1.0)], ), # RFC 7231, section 5.3.4 ("compress, gzip", [("compress", 1.0), ("gzip", 1.0)]), ("", []), ("*", [("*", 1.0)]), ("compress;q=0.5, gzip;q=1.0", [("compress", 0.5), ("gzip", 1.0)]), ( "gzip;q=1.0, identity; q=0.5, *;q=0", [("gzip", 1.0), ("identity", 0.5), ("*", 0.0)], ), ], ) def test_parse__valid_header(self, value, expected_list): returned = AcceptEncoding.parse(value=value) list_of_returned = list(returned) assert list_of_returned == expected_list class TestAcceptEncodingValidHeader: def test_parse__inherited(self): returned = AcceptEncodingValidHeader.parse( value=",,\t gzip;q=1.0, identity; q=0.5, *;q=0 \t ," ) list_of_returned = list(returned) assert list_of_returned == [("gzip", 1.0), ("identity", 0.5), ("*", 0.0)] @pytest.mark.parametrize( "header_value", [", ", "gzip;q=1.0, identity; q =0.5, *;q=0"] ) def test___init___invalid_header(self, header_value): with pytest.raises(ValueError): AcceptEncodingValidHeader(header_value=header_value) def test___init___valid_header(self): header_value = ",,\t gzip;q=1.0, identity; q=0, *;q=0.5 \t ," instance = AcceptEncodingValidHeader(header_value=header_value) assert instance.header_value == header_value assert instance.parsed == [("gzip", 1.0), ("identity", 0.0), ("*", 0.5)] assert instance._parsed_nonzero == [("gzip", 1.0), ("*", 0.5)] assert isinstance(instance, AcceptEncoding) def test___add___None(self): left_operand = AcceptEncodingValidHeader(header_value="gzip") result = left_operand + None assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize("right_operand", [", ", [", "], (", ",), {", ": 1.0}]) def test___add___invalid_value(self, right_operand): left_operand = AcceptEncodingValidHeader(header_value="gzip") result = left_operand + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand def test___add___other_type_with_invalid___str__(self): left_operand = AcceptEncodingValidHeader(header_value="gzip") class Other: def __str__(self): return ", " right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize("value", ["", [], (), {}]) def test___add___valid_empty_value(self, value): left_operand = AcceptEncodingValidHeader(header_value="gzip") result = left_operand + value assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand def test___add___other_type_with_valid___str___empty(self): left_operand = AcceptEncodingValidHeader(header_value="gzip") class Other: def __str__(self): return "" result = left_operand + Other() assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize( "value, value_as_header", [ ("compress;q=0.5, deflate;q=0, *", "compress;q=0.5, deflate;q=0, *"), (["compress;q=0.5", "deflate;q=0", "*"], "compress;q=0.5, deflate;q=0, *"), ( [("compress", 0.5), ("deflate", 0.0), ("*", 1.0)], "compress;q=0.5, deflate;q=0, *", ), (("compress;q=0.5", "deflate;q=0", "*"), "compress;q=0.5, deflate;q=0, *"), ( (("compress", 0.5), ("deflate", 0.0), ("*", 1.0)), "compress;q=0.5, deflate;q=0, *", ), ( {"compress": 0.5, "deflate": 0.0, "*": 1.0}, "*, compress;q=0.5, deflate;q=0", ), ], ) def test___add___valid_value(self, value, value_as_header): header = ",\t ,gzip, identity;q=0.333," result = AcceptEncodingValidHeader(header_value=header) + value assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == header + ", " + value_as_header def test___add___other_type_with_valid___str___not_empty(self): header = ",\t ,gzip, identity;q=0.333," class Other: def __str__(self): return "compress;q=0.5, deflate;q=0, *" right_operand = Other() result = AcceptEncodingValidHeader(header_value=header) + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == header + ", " + str(right_operand) def test___add___AcceptEncodingValidHeader_header_value_empty(self): left_operand = AcceptEncodingValidHeader( header_value=",\t ,gzip, identity;q=0.333," ) right_operand = AcceptEncodingValidHeader(header_value="") result = left_operand + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand def test___add___AcceptEncodingValidHeader_header_value_not_empty(self): left_operand = AcceptEncodingValidHeader( header_value=",\t ,gzip, identity;q=0.333," ) right_operand = AcceptEncodingValidHeader( header_value="compress;q=0.5, deflate;q=0, *" ) result = left_operand + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert ( result.header_value == left_operand.header_value + ", " + right_operand.header_value ) def test___add___AcceptEncodingNoHeader(self): valid_header_instance = AcceptEncodingValidHeader(header_value="gzip") result = valid_header_instance + AcceptEncodingNoHeader() assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == valid_header_instance.header_value assert result is not valid_header_instance @pytest.mark.parametrize("header_value", [", ", "compress;q=1.001"]) def test___add___AcceptEncodingInvalidHeader(self, header_value): valid_header_instance = AcceptEncodingValidHeader(header_value="gzip") result = valid_header_instance + AcceptEncodingInvalidHeader( header_value=header_value ) assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == valid_header_instance.header_value assert result is not valid_header_instance def test___bool__(self): instance = AcceptEncodingValidHeader(header_value="gzip") returned = bool(instance) assert returned is True @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): accept = AcceptEncodingValidHeader("gzip, compress") assert "gzip" in accept assert "deflate" not in accept for mask in ["*", "gzip", "gZIP"]: assert "gzip" in AcceptEncodingValidHeader(mask) @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptEncodingValidHeader( header_value="gzip; q=0.5, *; q=0, deflate; q=0.8, compress" ) assert list(instance) == ["compress", "deflate", "gzip"] def test___radd___None(self): right_operand = AcceptEncodingValidHeader(header_value="gzip") result = None + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize("left_operand", [", ", [", "], (", ",), {", ": 1.0}]) def test___radd___invalid_value(self, left_operand): right_operand = AcceptEncodingValidHeader(header_value="gzip") result = left_operand + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___radd___other_type_with_invalid___str__(self): right_operand = AcceptEncodingValidHeader(header_value="gzip") class Other: def __str__(self): return ", " result = Other() + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize("value", ["", [], (), {}]) def test___radd___valid_empty_value(self, value): right_operand = AcceptEncodingValidHeader(header_value="gzip") result = value + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___radd___other_type_with_valid___str___empty(self): right_operand = AcceptEncodingValidHeader(header_value="gzip") class Other: def __str__(self): return "" result = Other() + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize( "value, value_as_header", [ ("compress;q=0.5, deflate;q=0, *", "compress;q=0.5, deflate;q=0, *"), (["compress;q=0.5", "deflate;q=0", "*"], "compress;q=0.5, deflate;q=0, *"), ( [("compress", 0.5), ("deflate", 0.0), ("*", 1.0)], "compress;q=0.5, deflate;q=0, *", ), (("compress;q=0.5", "deflate;q=0", "*"), "compress;q=0.5, deflate;q=0, *"), ( (("compress", 0.5), ("deflate", 0.0), ("*", 1.0)), "compress;q=0.5, deflate;q=0, *", ), ( {"compress": 0.5, "deflate": 0.0, "*": 1.0}, "*, compress;q=0.5, deflate;q=0", ), ], ) def test___radd___valid_non_empty_value(self, value, value_as_header): header = ",\t ,gzip, identity;q=0.333," result = value + AcceptEncodingValidHeader(header_value=header) assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == value_as_header + ", " + header def test___radd___other_type_with_valid___str___not_empty(self): header = ",\t ,gzip, identity;q=0.333," class Other: def __str__(self): return "compress;q=0.5, deflate;q=0, *" left_operand = Other() result = left_operand + AcceptEncodingValidHeader(header_value=header) assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == str(left_operand) + ", " + header @pytest.mark.parametrize( "header_value, expected_returned", [ ("", ""), ( ",\t, a ;\t q=0.20 , b ,',", # single quote is valid character in token """""", ), ], ) def test___repr__(self, header_value, expected_returned): instance = AcceptEncodingValidHeader(header_value=header_value) assert repr(instance) == expected_returned @pytest.mark.parametrize( "header_value, expected_returned", [("", ""), (",\t, a ;\t q=0.20 , b ,',", "a;q=0.2, b, '")], ) def test___str__(self, header_value, expected_returned): instance = AcceptEncodingValidHeader(header_value=header_value) assert str(instance) == expected_returned @pytest.mark.parametrize( "header_value, offers, expected_returned", [ ("", [], []), ("gzip, compress", [], []), ("", ["gzip", "deflate"], []), ("", ["gzip", "identity"], [("identity", 1.0)]), ("compress, deflate, gzip", ["identity"], [("identity", 1.0)]), ("compress, identity;q=0, gzip", ["identity"], []), # *;q=0 does not make sense, but is valid ("*;q=0", ["identity"], []), ("*;q=0, deflate, gzip", ["identity"], []), ("*;q=0, deflate, identity;q=0, gzip", ["identity"], []), ("*;q=0, deflate, identity;q=0.1, gzip", ["identity"], [("identity", 0.1)]), ( "compress, deflate, gzip", ["identity", "gzip"], [("identity", 1.0), ("gzip", 1.0)], ), ( "compress, deflate, gzip", ["gzip", "identity"], [("gzip", 1.0), ("identity", 1.0)], ), ( "IDentity;q=0.5, deflATE;q=0, gZIP;q=0, COMPress", ["GZip", "DEFlate", "IDENTity", "comPRESS"], [("comPRESS", 1.0), ("IDENTity", 0.5)], ), ( "compress;q=0, identity, *;q=0.5, identity;q=0, *;q=0, compress", # does not make sense, but is valid ["compress", "identity", "deflate", "gzip"], [("identity", 1.0), ("deflate", 0.5), ("gzip", 0.5)], ), ], ) def test_acceptable_offers(self, header_value, offers, expected_returned): instance = AcceptEncodingValidHeader(header_value=header_value) returned = instance.acceptable_offers(offers=offers) assert returned == expected_returned @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptEncodingValidHeader("gzip, iso-8859-5") assert accept.best_match(["gzip", "iso-8859-5"]) == "gzip" assert accept.best_match(["iso-8859-5", "gzip"]) == "iso-8859-5" assert accept.best_match([("iso-8859-5", 0.5), "gzip"]) == "gzip" assert accept.best_match([("iso-8859-5", 0.5), ("gzip", 0.4)]) == "iso-8859-5" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_with_one_lower_q(self): accept = AcceptEncodingValidHeader("gzip, compress;q=0.5") assert accept.best_match(["gzip", "compress"]) == "gzip" accept = AcceptEncodingValidHeader("gzip;q=0.5, compress") assert accept.best_match(["gzip", "compress"]) == "compress" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_with_complex_q(self): accept = AcceptEncodingValidHeader("gzip, compress;q=0.55, deflate;q=0.59") assert accept.best_match(["gzip", "compress"]) == "gzip" accept = AcceptEncodingValidHeader( "gzip;q=0.5, compress;q=0.586, deflate;q=0.596" ) assert accept.best_match(["gzip", "deflate"]) == "deflate" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match_mixedcase(self): accept = AcceptEncodingValidHeader("gZiP; q=0.2, COMPress; Q=0.4, *; q=0.05") assert accept.best_match(["gzIP"]) == "gzIP" assert accept.best_match(["DeFlAte"]) == "DeFlAte" assert accept.best_match(["deflaTe", "compRess", "UtF-8"]) == "compRess" @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test_best_match_zero_quality(self): assert AcceptEncodingValidHeader("deflate, *;q=0").best_match(["gzip"]) is None assert "content-coding" not in AcceptEncodingValidHeader("*;q=0") @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): accept = AcceptEncodingValidHeader("gzip") assert accept.quality("gzip") == 1 accept = AcceptEncodingValidHeader("gzip;q=0.5") assert accept.quality("gzip") == 0.5 @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality_not_found(self): accept = AcceptEncodingValidHeader("gzip") assert accept.quality("compress") is None class TestAcceptEncodingNoHeader: def test_parse__inherited(self): returned = AcceptEncodingNoHeader.parse( value=",,\t gzip;q=1.0, identity; q=0.5, *;q=0 \t ," ) list_of_returned = list(returned) assert list_of_returned == [("gzip", 1.0), ("identity", 0.5), ("*", 0.0)] def test___init__(self): instance = AcceptEncodingNoHeader() assert instance.header_value is None assert instance.parsed is None assert instance._parsed_nonzero is None assert isinstance(instance, AcceptEncoding) def test___add___None(self): left_operand = AcceptEncodingNoHeader() result = left_operand + None assert isinstance(result, AcceptEncodingNoHeader) @pytest.mark.parametrize("right_operand", [", ", [", "], (", ",), {", ": 1.0}]) def test___add___invalid_value(self, right_operand): left_operand = AcceptEncodingNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptEncodingNoHeader) def test___add___other_type_with_invalid___str__(self): left_operand = AcceptEncodingNoHeader() class Other: def __str__(self): return ", " right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptEncodingNoHeader) @pytest.mark.parametrize("value", ["", [], (), {}]) def test___add___valid_empty_value(self, value): left_operand = AcceptEncodingNoHeader() result = left_operand + value assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == "" def test___add___other_type_with_valid___str___empty(self): left_operand = AcceptEncodingNoHeader() class Other: def __str__(self): return "" result = left_operand + Other() assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == "" @pytest.mark.parametrize( "value, value_as_header", [ ("compress;q=0.5, deflate;q=0, *", "compress;q=0.5, deflate;q=0, *"), (["compress;q=0.5", "deflate;q=0", "*"], "compress;q=0.5, deflate;q=0, *"), ( [("compress", 0.5), ("deflate", 0.0), ("*", 1.0)], "compress;q=0.5, deflate;q=0, *", ), (("compress;q=0.5", "deflate;q=0", "*"), "compress;q=0.5, deflate;q=0, *"), ( (("compress", 0.5), ("deflate", 0.0), ("*", 1.0)), "compress;q=0.5, deflate;q=0, *", ), ( {"compress": 0.5, "deflate": 0.0, "*": 1.0}, "*, compress;q=0.5, deflate;q=0", ), ], ) def test___add___valid_value(self, value, value_as_header): result = AcceptEncodingNoHeader() + value assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == value_as_header def test___add___other_type_with_valid___str___not_empty(self): class Other: def __str__(self): return "compress;q=0.5, deflate;q=0, *" right_operand = Other() result = AcceptEncodingNoHeader() + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == str(right_operand) def test___add___AcceptEncodingValidHeader_header_value_empty(self): right_operand = AcceptEncodingValidHeader(header_value="") result = AcceptEncodingNoHeader() + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___add___AcceptEncodingValidHeader_header_value_not_empty(self): right_operand = AcceptEncodingValidHeader( header_value="compress;q=0.5, deflate;q=0, *" ) result = AcceptEncodingNoHeader() + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value def test___add___AcceptEncodingNoHeader(self): left_operand = AcceptEncodingNoHeader() right_operand = AcceptEncodingNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptEncodingNoHeader) assert result is not left_operand assert result is not right_operand @pytest.mark.parametrize("header_value", [", ", "compress;q=1.001"]) def test___add___AcceptEncodingInvalidHeader(self, header_value): left_operand = AcceptEncodingNoHeader() result = left_operand + AcceptEncodingInvalidHeader(header_value=header_value) assert isinstance(result, AcceptEncodingNoHeader) assert result is not left_operand def test___bool__(self): instance = AcceptEncodingNoHeader() returned = bool(instance) assert returned is False @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): instance = AcceptEncodingNoHeader() returned = "content-coding" in instance assert returned is True @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptEncodingNoHeader() returned = list(instance) assert returned == [] def test___radd___None(self): right_operand = AcceptEncodingNoHeader() result = None + right_operand assert isinstance(result, AcceptEncodingNoHeader) assert result is not right_operand @pytest.mark.parametrize("left_operand", [", ", [", "], (", ",), {", ": 1.0}]) def test___radd___invalid_value(self, left_operand): right_operand = AcceptEncodingNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptEncodingNoHeader) assert result is not right_operand def test___radd___other_type_with_invalid___str__(self): right_operand = AcceptEncodingNoHeader() class Other: def __str__(self): return ", " result = Other() + right_operand assert isinstance(result, AcceptEncodingNoHeader) assert result is not right_operand @pytest.mark.parametrize("value", ["", [], (), {}]) def test___radd___valid_empty_value(self, value): result = value + AcceptEncodingNoHeader() assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == "" def test___radd___other_type_with_valid___str___empty(self): class Other: def __str__(self): return "" result = Other() + AcceptEncodingNoHeader() assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == "" @pytest.mark.parametrize( "value, value_as_header", [ ("compress;q=0.5, deflate;q=0, *", "compress;q=0.5, deflate;q=0, *"), (["compress;q=0.5", "deflate;q=0", "*"], "compress;q=0.5, deflate;q=0, *"), ( [("compress", 0.5), ("deflate", 0.0), ("*", 1.0)], "compress;q=0.5, deflate;q=0, *", ), (("compress;q=0.5", "deflate;q=0", "*"), "compress;q=0.5, deflate;q=0, *"), ( (("compress", 0.5), ("deflate", 0.0), ("*", 1.0)), "compress;q=0.5, deflate;q=0, *", ), ( {"compress": 0.5, "deflate": 0.0, "*": 1.0}, "*, compress;q=0.5, deflate;q=0", ), ], ) def test___radd___valid_non_empty_value(self, value, value_as_header): result = value + AcceptEncodingNoHeader() assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == value_as_header def test___radd___other_type_with_valid___str___not_empty(self): class Other: def __str__(self): return "compress;q=0.5, deflate;q=0, *" left_operand = Other() result = left_operand + AcceptEncodingNoHeader() assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == str(left_operand) def test___repr__(self): instance = AcceptEncodingNoHeader() assert repr(instance) == "" def test___str__(self): instance = AcceptEncodingNoHeader() assert str(instance) == "" def test_acceptable_offers(self): instance = AcceptEncodingNoHeader() returned = instance.acceptable_offers(offers=["a", "b", "c"]) assert returned == [("a", 1.0), ("b", 1.0), ("c", 1.0)] @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptEncodingNoHeader() assert accept.best_match(["gzip", "compress"]) == "gzip" assert accept.best_match([("gzip", 1), ("compress", 0.5)]) == "gzip" assert accept.best_match([("gzip", 0.5), ("compress", 1)]) == "compress" assert accept.best_match([("gzip", 0.5), "compress"]) == "compress" assert ( accept.best_match([("gzip", 0.5), "compress"], default_match=True) == "compress" ) assert ( accept.best_match([("gzip", 0.5), "compress"], default_match=False) == "compress" ) assert accept.best_match([], default_match="fallback") == "fallback" @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): instance = AcceptEncodingNoHeader() returned = instance.quality(offer="content-coding") assert returned == 1.0 class TestAcceptEncodingInvalidHeader: def test_parse__inherited(self): returned = AcceptEncodingInvalidHeader.parse( value=",,\t gzip;q=1.0, identity; q=0.5, *;q=0 \t ," ) list_of_returned = list(returned) assert list_of_returned == [("gzip", 1.0), ("identity", 0.5), ("*", 0.0)] def test___init__(self): header_value = "invalid header" instance = AcceptEncodingInvalidHeader(header_value=header_value) assert instance.header_value == header_value assert instance.parsed is None assert instance._parsed_nonzero is None assert isinstance(instance, AcceptEncoding) def test___add___None(self): left_operand = AcceptEncodingInvalidHeader(header_value=", ") result = left_operand + None assert isinstance(result, AcceptEncodingNoHeader) @pytest.mark.parametrize("right_operand", [", ", [", "], (", ",), {", ": 1.0}]) def test___add___invalid_value(self, right_operand): left_operand = AcceptEncodingInvalidHeader(header_value="invalid header") result = left_operand + right_operand assert isinstance(result, AcceptEncodingNoHeader) def test___add___other_type_with_invalid___str__(self): left_operand = AcceptEncodingInvalidHeader(header_value="invalid header") class Other: def __str__(self): return ", " right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptEncodingNoHeader) @pytest.mark.parametrize("value", ["", [], (), {}]) def test___add___valid_empty_value(self, value): left_operand = AcceptEncodingInvalidHeader(header_value=", ") result = left_operand + value assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == "" def test___add___other_type_with_valid___str___empty(self): left_operand = AcceptEncodingInvalidHeader(header_value=", ") class Other: def __str__(self): return "" result = left_operand + Other() assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == "" @pytest.mark.parametrize( "value, value_as_header", [ ("compress;q=0.5, deflate;q=0, *", "compress;q=0.5, deflate;q=0, *"), (["compress;q=0.5", "deflate;q=0", "*"], "compress;q=0.5, deflate;q=0, *"), ( [("compress", 0.5), ("deflate", 0.0), ("*", 1.0)], "compress;q=0.5, deflate;q=0, *", ), (("compress;q=0.5", "deflate;q=0", "*"), "compress;q=0.5, deflate;q=0, *"), ( (("compress", 0.5), ("deflate", 0.0), ("*", 1.0)), "compress;q=0.5, deflate;q=0, *", ), ( {"compress": 0.5, "deflate": 0.0, "*": 1.0}, "*, compress;q=0.5, deflate;q=0", ), ], ) def test___add___valid_value(self, value, value_as_header): result = AcceptEncodingInvalidHeader(header_value=", ") + value assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == value_as_header def test___add___other_type_with_valid___str___not_empty(self): class Other: def __str__(self): return "*, compress;q=0.5, deflate;q=0" right_operand = Other() result = AcceptEncodingInvalidHeader(header_value=", ") + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == str(right_operand) def test___add___AcceptEncodingValidHeader_header_value_empty(self): left_operand = AcceptEncodingInvalidHeader(header_value=", ") right_operand = AcceptEncodingValidHeader(header_value="") result = left_operand + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___add___AcceptEncodingValidHeader_header_value_not_empty(self): left_operand = AcceptEncodingInvalidHeader(header_value=", ") right_operand = AcceptEncodingValidHeader( header_value="compress;q=0.5, deflate;q=0, *" ) result = left_operand + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == right_operand.header_value def test___add___AcceptEncodingNoHeader(self): left_operand = AcceptEncodingInvalidHeader(header_value=", ") right_operand = AcceptEncodingNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptEncodingNoHeader) assert result is not right_operand @pytest.mark.parametrize("header_value", [", ", "compress;q=1.001"]) def test___add___AcceptEncodingInvalidHeader(self, header_value): result = AcceptEncodingInvalidHeader( header_value="gzip;;q=1" ) + AcceptEncodingInvalidHeader(header_value=header_value) assert isinstance(result, AcceptEncodingNoHeader) def test___bool__(self): instance = AcceptEncodingInvalidHeader(header_value=", ") returned = bool(instance) assert returned is False @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): instance = AcceptEncodingInvalidHeader(header_value=", ") returned = "content-coding" in instance assert returned is True @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptEncodingInvalidHeader(header_value=", ") returned = list(instance) assert returned == [] def test___radd___None(self): right_operand = AcceptEncodingInvalidHeader(header_value=", ") result = None + right_operand assert isinstance(result, AcceptEncodingNoHeader) @pytest.mark.parametrize("left_operand", [", ", [", "], (", ",), {", ": 1.0}]) def test___radd___invalid_value(self, left_operand): right_operand = AcceptEncodingInvalidHeader(header_value="gzip;q= 1") result = left_operand + right_operand assert isinstance(result, AcceptEncodingNoHeader) def test___radd___other_type_with_invalid___str__(self): right_operand = AcceptEncodingInvalidHeader(header_value="gzip;q= 1") class Other: def __str__(self): return ", " result = Other() + right_operand assert isinstance(result, AcceptEncodingNoHeader) @pytest.mark.parametrize("value", ["", [], (), {}]) def test___radd___valid_empty_value(self, value): right_operand = AcceptEncodingInvalidHeader(header_value=", ") result = value + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == "" def test___radd___other_type_with_valid___str___empty(self): right_operand = AcceptEncodingInvalidHeader(header_value=", ") class Other: def __str__(self): return "" result = Other() + right_operand assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == "" @pytest.mark.parametrize( "value, value_as_header", [ ("compress;q=0.5, deflate;q=0, *", "compress;q=0.5, deflate;q=0, *"), (["compress;q=0.5", "deflate;q=0", "*"], "compress;q=0.5, deflate;q=0, *"), ( [("compress", 0.5), ("deflate", 0.0), ("*", 1.0)], "compress;q=0.5, deflate;q=0, *", ), (("compress;q=0.5", "deflate;q=0", "*"), "compress;q=0.5, deflate;q=0, *"), ( (("compress", 0.5), ("deflate", 0.0), ("*", 1.0)), "compress;q=0.5, deflate;q=0, *", ), ( {"compress": 0.5, "deflate": 0.0, "*": 1.0}, "*, compress;q=0.5, deflate;q=0", ), ], ) def test___radd___valid_non_empty_value(self, value, value_as_header): result = value + AcceptEncodingInvalidHeader(header_value=", ") assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == value_as_header def test___radd___other_type_with_valid___str___not_empty(self): class Other: def __str__(self): return "compress;q=0.5, deflate;q=0, *" left_operand = Other() result = left_operand + AcceptEncodingInvalidHeader(header_value=", ") assert isinstance(result, AcceptEncodingValidHeader) assert result.header_value == str(left_operand) def test___repr__(self): instance = AcceptEncodingInvalidHeader(header_value="\x00") assert repr(instance) == "" def test___str__(self): instance = AcceptEncodingInvalidHeader(header_value=", ") assert str(instance) == "" def test_acceptable_offers(self): instance = AcceptEncodingInvalidHeader(header_value=", ") returned = instance.acceptable_offers(offers=["a", "b", "c"]) assert returned == [("a", 1.0), ("b", 1.0), ("c", 1.0)] @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self): accept = AcceptEncodingInvalidHeader(header_value=", ") assert accept.best_match(["gzip", "compress"]) == "gzip" assert accept.best_match([("gzip", 1), ("compress", 0.5)]) == "gzip" assert accept.best_match([("gzip", 0.5), ("compress", 1)]) == "compress" assert accept.best_match([("gzip", 0.5), "compress"]) == "compress" assert ( accept.best_match([("gzip", 0.5), "compress"], default_match=True) == "compress" ) assert ( accept.best_match([("gzip", 0.5), "compress"], default_match=False) == "compress" ) assert accept.best_match([], default_match="fallback") == "fallback" @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): instance = AcceptEncodingInvalidHeader(header_value=", ") returned = instance.quality(offer="content-coding") assert returned == 1.0 class TestCreateAcceptEncodingHeader: def test_header_value_is_None(self): header_value = None returned = create_accept_encoding_header(header_value=header_value) assert isinstance(returned, AcceptEncodingNoHeader) assert returned.header_value == header_value returned2 = create_accept_encoding_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value def test_header_value_is_valid(self): header_value = "gzip, identity;q=0.9" returned = create_accept_encoding_header(header_value=header_value) assert isinstance(returned, AcceptEncodingValidHeader) assert returned.header_value == header_value returned2 = create_accept_encoding_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value @pytest.mark.parametrize("header_value", [", ", "gzip;q= 1"]) def test_header_value_is_invalid(self, header_value): returned = create_accept_encoding_header(header_value=header_value) assert isinstance(returned, AcceptEncodingInvalidHeader) assert returned.header_value == header_value returned2 = create_accept_encoding_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value class TestAcceptEncodingProperty: def test_fget_header_is_None(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": None}) property_ = accept_encoding_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptEncodingNoHeader) def test_fget_header_is_valid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": "gzip"}) property_ = accept_encoding_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptEncodingValidHeader) def test_fget_header_is_invalid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": ", "}) property_ = accept_encoding_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptEncodingInvalidHeader) def test_fset_value_is_None(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": "gzip"}) property_ = accept_encoding_property() property_.fset(request=request, value=None) assert isinstance(request.accept_encoding, AcceptEncodingNoHeader) assert "HTTP_ACCEPT_ENCODING" not in request.environ def test_fset_value_is_invalid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": "gzip"}) property_ = accept_encoding_property() property_.fset(request=request, value=", ") assert isinstance(request.accept_encoding, AcceptEncodingInvalidHeader) assert request.environ["HTTP_ACCEPT_ENCODING"] == ", " def test_fset_value_is_valid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": "gzip"}) property_ = accept_encoding_property() property_.fset(request=request, value="compress") assert isinstance(request.accept_encoding, AcceptEncodingValidHeader) assert request.environ["HTTP_ACCEPT_ENCODING"] == "compress" @pytest.mark.parametrize( "value, value_as_header", [ ("gzip;q=0.5, compress;q=0, deflate", "gzip;q=0.5, compress;q=0, deflate"), ( [("gzip", 0.5), ("compress", 0.0), "deflate"], "gzip;q=0.5, compress;q=0, deflate", ), ( (("gzip", 0.5), ("compress", 0.0), "deflate"), "gzip;q=0.5, compress;q=0, deflate", ), ( {"gzip": 0.5, "compress": 0.0, "deflate": 1.0}, "deflate, gzip;q=0.5, compress;q=0", ), ], ) def test_fset_value_types(self, value, value_as_header): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": ""}) property_ = accept_encoding_property() property_.fset(request=request, value=value) assert isinstance(request.accept_encoding, AcceptEncodingValidHeader) assert request.environ["HTTP_ACCEPT_ENCODING"] == value_as_header def test_fset_other_type_with_valid___str__(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": ""}) property_ = accept_encoding_property() class Other: def __str__(self): return "gzip;q=0.5, compress;q=0, deflate" value = Other() property_.fset(request=request, value=value) assert isinstance(request.accept_encoding, AcceptEncodingValidHeader) assert request.environ["HTTP_ACCEPT_ENCODING"] == str(value) def test_fset_AcceptEncodingNoHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": ""}) property_ = accept_encoding_property() header = AcceptEncodingNoHeader() property_.fset(request=request, value=header) assert isinstance(request.accept_encoding, AcceptEncodingNoHeader) assert "HTTP_ACCEPT_ENCODING" not in request.environ def test_fset_AcceptEncodingValidHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": ""}) property_ = accept_encoding_property() header = AcceptEncodingValidHeader("gzip") property_.fset(request=request, value=header) assert isinstance(request.accept_encoding, AcceptEncodingValidHeader) assert request.environ["HTTP_ACCEPT_ENCODING"] == header.header_value def test_fset_AcceptEncodingInvalidHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": "gzip"}) property_ = accept_encoding_property() header = AcceptEncodingInvalidHeader(", ") property_.fset(request=request, value=header) assert isinstance(request.accept_encoding, AcceptEncodingInvalidHeader) assert request.environ["HTTP_ACCEPT_ENCODING"] == header.header_value def test_fdel_header_key_in_environ(self): request = Request.blank("/", environ={"HTTP_ACCEPT_ENCODING": "gzip"}) property_ = accept_encoding_property() property_.fdel(request=request) assert isinstance(request.accept_encoding, AcceptEncodingNoHeader) assert "HTTP_ACCEPT_ENCODING" not in request.environ def test_fdel_header_key_not_in_environ(self): request = Request.blank("/") property_ = accept_encoding_property() property_.fdel(request=request) assert isinstance(request.accept_encoding, AcceptEncodingNoHeader) assert "HTTP_ACCEPT_ENCODING" not in request.environ class TestAcceptLanguage: @pytest.mark.parametrize( "value", [ "", "*s", "*-a", "a-*", "a" * 9, "a-" + "a" * 9, "a-a-" + "a" * 9, "-", "a-", "-a", "---", "--a", "1-a", "1-a-a", "en_gb", "en/gb", "foo, bar, baz;q= 0.001", "foo , ,bar,charlie ", ], ) def test_parse__invalid_header(self, value): with pytest.raises(ValueError): AcceptLanguage.parse(value=value) @pytest.mark.parametrize( "value, expected_list", [ ("*", [("*", 1.0)]), ("fR;q=0.5", [("fR", 0.5)]), ("zh-Hant;q=0.500", [("zh-Hant", 0.5)]), ("zh-Hans-CN;q=1", [("zh-Hans-CN", 1.0)]), ("de-CH-x-phonebk;q=1.0", [("de-CH-x-phonebk", 1.0)]), ("az-Arab-x-AZE-derbend;q=1.00", [("az-Arab-x-AZE-derbend", 1.0)]), ("zh-CN-a-myExt-x-private;q=1.000", [("zh-CN-a-myExt-x-private", 1.0)]), ("aaaaaaaa", [("aaaaaaaa", 1.0)]), ("aaaaaaaa-a", [("aaaaaaaa-a", 1.0)]), ("aaaaaaaa-aaaaaaaa", [("aaaaaaaa-aaaaaaaa", 1.0)]), ("a-aaaaaaaa-aaaaaaaa", [("a-aaaaaaaa-aaaaaaaa", 1.0)]), ("aaaaaaaa-a-aaaaaaaa", [("aaaaaaaa-a-aaaaaaaa", 1.0)]), ( "zh-Hant;q=0.372,zh-CN-a-myExt-x-private;q=0.977,de,*;q=0.000", [ ("zh-Hant", 0.372), ("zh-CN-a-myExt-x-private", 0.977), ("de", 1.0), ("*", 0.0), ], ), ( ",\t foo \t;\t q=0.345,, bar ; Q=0.456 \t, ,\tcharlie \t,, ,", [("foo", 0.345), ("bar", 0.456), ("charlie", 1.0)], ), # RFC 7230 Section 7 ("foo,bar", [("foo", 1.0), ("bar", 1.0)]), ("foo, bar,", [("foo", 1.0), ("bar", 1.0)]), # RFC 7230 Errata ID: 4169 ("foo , ,bar,charlie", [("foo", 1.0), ("bar", 1.0), ("charlie", 1.0)]), ], ) def test_parse__valid_header(self, value, expected_list): returned = AcceptLanguage.parse(value=value) list_of_returned = list(returned) assert list_of_returned == expected_list class TestAcceptLanguageValidHeader: @pytest.mark.parametrize("header_value", ["", ", da;q=0.2, en-gb;q=0.3 "]) def test___init___invalid_header(self, header_value): with pytest.raises(ValueError): AcceptLanguageValidHeader(header_value=header_value) def test___init___valid_header(self): header_value = "zh-Hant;q=0.372,zh-CN-a-myExt-x-private;q=0.977,de,*;q=0.000" instance = AcceptLanguageValidHeader(header_value=header_value) assert instance.header_value == header_value assert instance.parsed == [ ("zh-Hant", 0.372), ("zh-CN-a-myExt-x-private", 0.977), ("de", 1.0), ("*", 0.0), ] assert instance._parsed_nonzero == [ ("zh-Hant", 0.372), ("zh-CN-a-myExt-x-private", 0.977), ("de", 1.0), ] assert isinstance(instance, AcceptLanguage) def test___add___None(self): left_operand = AcceptLanguageValidHeader(header_value="en") result = left_operand + None assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize( "right_operand", [ "", [], (), {}, "en_gb", ["en_gb"], ("en_gb",), {"en_gb": 1.0}, ",", [","], (",",), {",": 1.0}, ], ) def test___add___invalid_value(self, right_operand): left_operand = AcceptLanguageValidHeader(header_value="en") result = left_operand + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize("str_", ["", "en_gb", ","]) def test___add___other_type_with_invalid___str__(self, str_): left_operand = AcceptLanguageValidHeader(header_value="en") class Other: def __str__(self): return str_ right_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == left_operand.header_value assert result is not left_operand @pytest.mark.parametrize( "value, value_as_header", [ ("en-gb;q=0.5, fr;q=0, es", "en-gb;q=0.5, fr;q=0, es"), ([("en-gb", 0.5), ("fr", 0.0), "es"], "en-gb;q=0.5, fr;q=0, es"), ((("en-gb", 0.5), ("fr", 0.0), "es"), "en-gb;q=0.5, fr;q=0, es"), ({"en-gb": 0.5, "fr": 0.0, "es": 1.0}, "es, en-gb;q=0.5, fr;q=0"), ], ) def test___add___valid_value(self, value, value_as_header): header = ",\t ,de, zh-Hans;q=0.333," result = AcceptLanguageValidHeader(header_value=header) + value assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == header + ", " + value_as_header def test___add___other_type_with_valid___str__(self): header = ",\t ,de, zh-Hans;q=0.333," class Other: def __str__(self): return "en-gb;q=0.5, fr;q=0, es" right_operand = Other() result = AcceptLanguageValidHeader(header_value=header) + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == header + ", " + str(right_operand) def test___add___AcceptLanguageValidHeader(self): header1 = ",\t ,de, zh-Hans;q=0.333," header2 = ", ,fr;q=0, \tes;q=1," result = AcceptLanguageValidHeader( header_value=header1 ) + AcceptLanguageValidHeader(header_value=header2) assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == header1 + ", " + header2 def test___add___AcceptLanguageNoHeader(self): valid_header_instance = AcceptLanguageValidHeader(header_value="es") result = valid_header_instance + AcceptLanguageNoHeader() assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == valid_header_instance.header_value assert result is not valid_header_instance @pytest.mark.parametrize("header_value", ["", "en_gb", ","]) def test___add___AcceptLanguageInvalidHeader(self, header_value): valid_header_instance = AcceptLanguageValidHeader(header_value="header") result = valid_header_instance + AcceptLanguageInvalidHeader( header_value=header_value ) assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == valid_header_instance.header_value assert result is not valid_header_instance def test___bool__(self): instance = AcceptLanguageValidHeader(header_value="valid-header") returned = bool(instance) assert returned is True @pytest.mark.parametrize( "header_value, offer", [ ("*", "da"), ("da", "DA"), ("en", "en-gb"), ("en-gb", "en-gb"), ("en-gb", "en"), ("en-gb", "en_GB"), ], ) @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains___in(self, header_value, offer): instance = AcceptLanguageValidHeader(header_value=header_value) assert offer in instance @pytest.mark.parametrize( "header_value, offer", [("en-gb", "en-us"), ("en-gb", "fr-fr"), ("en-gb", "fr"), ("en", "fr-fr")], ) @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains___not_in(self, header_value, offer): instance = AcceptLanguageValidHeader(header_value=header_value) assert offer not in instance @pytest.mark.parametrize( "header_value, expected_list", [ ("fr;q=0, jp;q=0", []), ("en-gb, da", ["en-gb", "da"]), ("en-gb;q=0.5, da;q=0.5", ["en-gb", "da"]), ( "de;q=0.8, de-DE-1996;q=0.5, de-Deva;q=0, de-Latn-DE", ["de-Latn-DE", "de", "de-DE-1996"], ), # __iter__ is currently a simple filter for the ranges in the header # with non-0 qvalues, and does not attempt to account for the special # meanings of q=0 and *: ("en-gb;q=0, *", ["*"]), ("de, de;q=0", ["de"]), ], ) @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self, header_value, expected_list): instance = AcceptLanguageValidHeader(header_value=header_value) assert list(instance) == expected_list def test___radd___None(self): right_operand = AcceptLanguageValidHeader(header_value="en") result = None + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize( "left_operand", [ "", [], (), {}, "en_gb", ["en_gb"], ("en_gb",), {"en_gb": 1.0}, ",", [","], (",",), {",": 1.0}, ], ) def test___radd___invalid_value(self, left_operand): right_operand = AcceptLanguageValidHeader(header_value="en") result = left_operand + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize("str_", ["", "en_gb", ","]) def test___radd___other_type_with_invalid___str__(self, str_): right_operand = AcceptLanguageValidHeader(header_value="en") class Other: def __str__(self): return str_ result = Other() + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand @pytest.mark.parametrize( "value, value_as_header", [ ("en-gb;q=0.5, fr;q=0, es", "en-gb;q=0.5, fr;q=0, es"), ([("en-gb", 0.5), ("fr", 0.0), "es"], "en-gb;q=0.5, fr;q=0, es"), ((("en-gb", 0.5), ("fr", 0.0), "es"), "en-gb;q=0.5, fr;q=0, es"), ({"en-gb": 0.5, "fr": 0.0, "es": 1.0}, "es, en-gb;q=0.5, fr;q=0"), ], ) def test___radd___valid_value(self, value, value_as_header): right_operand = AcceptLanguageValidHeader( header_value=",\t ,de, zh-Hans;q=0.333," ) result = value + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert ( result.header_value == value_as_header + ", " + right_operand.header_value ) def test___radd___other_type_with_valid___str__(self): right_operand = AcceptLanguageValidHeader( header_value=",\t ,de, zh-Hans;q=0.333," ) class Other: def __str__(self): return "en-gb;q=0.5, fr;q=0, es" left_operand = Other() result = left_operand + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert ( result.header_value == str(left_operand) + ", " + right_operand.header_value ) def test___repr__(self): instance = AcceptLanguageValidHeader(header_value=",da;q=0.200,en-gb;q=0.300") assert repr(instance) == "" def test___str__(self): header_value = ", \t,de;q=0.000 \t, es;q=1.000, zh, jp;q=0.210 ," instance = AcceptLanguageValidHeader(header_value=header_value) assert str(instance) == "de;q=0, es, zh, jp;q=0.21" @pytest.mark.parametrize( "header_value, language_tags, expected_returned", [ # Example from RFC 4647, Section 3.4 ( "de-de", ["de", "de-DE-1996", "de-Deva", "de-Latn-DE"], [("de-DE-1996", 1.0)], ), # Empty `language_tags` ("a", [], []), # No matches ("a, b", ["c", "d"], []), # Several ranges and tags, no matches ("a-b;q=0.9, c-d;q=0.5, e-f", ("a", "b", "c", "d", "e", "f"), []), # Case-insensitive match ("foO, BaR", ["foo", "bar"], [("foo", 1.0), ("bar", 1.0)]), # If a tag matches a non-'*' range with q=0, tag is filtered out ("b-c, a, b;q=0, d;q=0", ["b-c", "a", "b-c-d", "d-e-f"], [("a", 1.0)]), # Match if a range exactly equals a tag ("d-e-f", ["a-b-c", "d-e-f"], [("d-e-f", 1.0)]), # Match if a range exactly equals a prefix of the tag such that the # first character following the prefix is '-' ( "a-b-c-d, a-b-c-d-e, a-b-c-d-f-g-h", ["a-b-c-d-f-g"], [("a-b-c-d-f-g", 1.0)], ), # '*', when it is the only range in the header, matches everything ("*", ["a", "b"], [("a", 1.0), ("b", 1.0)]), # '*' range matches only tags not matched by any other range ( "*;q=0.2, a;q=0.5, b", ["a-a", "b-a", "c-a", "d-a"], [("b-a", 1.0), ("a-a", 0.5), ("c-a", 0.2), ("d-a", 0.2)], ), # '*' range without a qvalue gives a matched qvalue of 1.0 ( "a;q=0.5, b, *", ["a-a", "b-a", "c-a", "d-a"], [("b-a", 1.0), ("c-a", 1.0), ("d-a", 1.0), ("a-a", 0.5)], ), # The qvalue for the '*' range works the same way as qvalues for # non-'*' ranges. ( "a;q=0.5, *;q=0.9", # (meaning: prefer anything other than 'a', with 'a' as a # fallback) ["a", "b"], [("b", 0.9), ("a", 0.5)], ), # More than one range matching the same tag: range with the highest # qvalue is matched ("a-b-c;q=0.7, a;q=0.9, a-b;q=0.8", ["a-b-c"], [("a-b-c", 0.9)]), # More than one range with the same qvalue matching the same tag: # the range in an earlier position in the header is matched ( "a-b-c;q=0.7, a;q=0.9, b;q=0.9, a-b;q=0.9", ["a-b-c", "b"], [("a-b-c", 0.9), ("b", 0.9)], ), # The returned list of tuples is sorted in descending order of qvalue ( "a;q=0.7, b;q=0.3, c, d;q=0.5", ["d", "c", "b", "a"], [("c", 1.0), ("a", 0.7), ("d", 0.5), ("b", 0.3)], ), # When qvalues are the same, the tag whose matched range appears # earlier in the header comes first ("a, c, b", ["b", "a", "c"], [("a", 1.0), ("c", 1.0), ("b", 1.0)]), # When many tags match the same range (so same qvalue and same # matched range position in header), they are returned in order of # their position in the `language_tags` argument ("a", ["a-b", "a", "a-b-c"], [("a-b", 1.0), ("a", 1.0), ("a-b-c", 1.0)]), # When a non-'*' range appears in the header more than once, we use # the first one for matching and ignore the others ( "a;q=0.5, c;q=0.6, b;q=0.7, c;q=0.9", ["a", "b", "c"], [("b", 0.7), ("c", 0.6), ("a", 0.5)], ), ( "a, b, c;q=0.5, c;q=0", ["a-a", "b-a", "c-a"], [("a-a", 1.0), ("b-a", 1.0), ("c-a", 0.5)], ), ( "a;q=0.5, c;q=0.9, b;q=0.9, c;q=0.9", ["a", "b", "c"], [("c", 0.9), ("b", 0.9), ("a", 0.5)], ), # When the '*' range appears in the header more than once, we use # the first one for matching and ignore the others ( "a;q=0.5, *;q=0.6, b;q=0.7, *;q=0.9", ["a", "b", "c"], [("b", 0.7), ("c", 0.6), ("a", 0.5)], ), ( "a, b, *;q=0.5, *;q=0", ["a-a", "b-a", "c-a"], [("a-a", 1.0), ("b-a", 1.0), ("c-a", 0.5)], ), ( "a;q=0.5, *;q=0.9, b;q=0.9, *;q=0.9", ["a", "b", "c"], [("c", 0.9), ("b", 0.9), ("a", 0.5)], ), # Both '*' and non-'*' ranges appearing more than once ( "a-b;q=0.5, c-d, *, a-b, c-d;q=0.3, *;q=0", ["a-b-c", "c-d-e", "e-f-g"], [("c-d-e", 1.0), ("e-f-g", 1.0), ("a-b-c", 0.5)], ), ], ) def test_basic_filtering(self, header_value, language_tags, expected_returned): instance = AcceptLanguageValidHeader(header_value=header_value) returned = instance.basic_filtering(language_tags=language_tags) assert returned == expected_returned @pytest.mark.parametrize( "header_value, offers, default_match, expected_returned", [ ("bar, *;q=0", ["foo"], None, None), ("en-gb, sr-Cyrl", ["sr-Cyrl", "en-gb"], None, "sr-Cyrl"), ("en-gb, sr-Cyrl", ["en-gb", "sr-Cyrl"], None, "en-gb"), ("en-gb, sr-Cyrl", [("sr-Cyrl", 0.5), "en-gb"], None, "en-gb"), ("en-gb, sr-Cyrl", [("sr-Cyrl", 0.5), ("en-gb", 0.4)], None, "sr-Cyrl"), ("en-gb, sr-Cyrl;q=0.5", ["en-gb", "sr-Cyrl"], None, "en-gb"), ("en-gb;q=0.5, sr-Cyrl", ["en-gb", "sr-Cyrl"], None, "sr-Cyrl"), ("en-gb, sr-Cyrl;q=0.55, es;q=0.59", ["en-gb", "sr-Cyrl"], None, "en-gb"), ( "en-gb;q=0.5, sr-Cyrl;q=0.586, es-419;q=0.597", ["en-gb", "es-419"], None, "es-419", ), ], ) @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self, header_value, offers, default_match, expected_returned): instance = AcceptLanguageValidHeader(header_value=header_value) returned = instance.best_match(offers=offers, default_match=default_match) assert returned == expected_returned def test_lookup_default_tag_and_default_cannot_both_be_None(self): instance = AcceptLanguageValidHeader(header_value="valid-header") with pytest.raises(TypeError): instance.lookup( language_tags=["tag"], default_range="language-range", default_tag=None, default=None, ) def test_lookup_default_range_cannot_be_asterisk(self): instance = AcceptLanguageValidHeader(header_value="valid-header") with pytest.raises(ValueError): instance.lookup( language_tags=["tag"], default_range="*", default_tag="default-tag", default=None, ) @pytest.mark.parametrize( ( "header_value, language_tags, default_range, default_tag, default" ", expected" ), [ # Each language range in the header is considered in turn, in # descending order of qvalue ( "aA;q=0.3, Bb, cC;q=0.7", ["Aa", "bB", "Cc"], None, "default-tag", None, "bB", ), # For ranges with the same qvalue, position in header is the # tiebreaker. ( "bB-Cc;q=0.8, aA;q=0.9, Bb;q=0.9", ["bb", "aa"], None, "default-tag", None, "aa", ), # Each language range represents the most specific tag that is an # acceptable match. Examples from RFC 4647, section 3.4, first # paragraph: ( "de-ch", ["de-CH-1996", "de-CH", "de"], None, "default-tag", None, "de-CH", ), ("de-ch", ["de-CH-1996", "de"], None, "default-tag", None, "de"), # The language range is progressively truncated from the end until # a matching language tag is located. From the example of a Lookup # Fallback Pattern in RFC 4647, section 3.4: ( "zh-Hant-CN-x-private1-private2", [ "zh-Hant-CN-x-private1-private2", "zh-Hant-CN-x-private1", "zh-Hant-CN-x", "zh-Hant-CN", "zh-Hant", "zh", ], None, "default-tag", None, "zh-Hant-CN-x-private1-private2", ), ( "zh-Hant-CN-x-private1-private2", [ "zh-Hant-CN-x-private1", "zh-Hant-CN-x", "zh-Hant-CN", "zh-Hant", "zh", ], None, "default-tag", None, "zh-Hant-CN-x-private1", ), ( "zh-Hant-CN-x-private1-private2", ["zh-Hant-CN-x", "zh-Hant-CN", "zh-Hant", "zh"], None, "default-tag", None, "zh-Hant-CN", ), ( "zh-Hant-CN-x-private1-private2", ["zh-Hant-CN", "zh-Hant", "zh"], None, "default-tag", None, "zh-Hant-CN", ), ( "zh-Hant-CN-x-private1-private2", ["zh-Hant", "zh"], None, "default-tag", None, "zh-Hant", ), ("zh-Hant-CN-x-private1-private2", ["zh"], None, "default-tag", None, "zh"), ( "zh-Hant-CN-x-private1-private2", ["some-other-tag-1", "some-other-tag-2"], None, "default-tag", None, "default-tag", ), # Further tests to check that single-letter or -digit subtags are # removed at the same time as their closest trailing subtag: ("AA-T-subtag", ["Aa-t", "aA"], None, "default-tag", None, "aA"), ("AA-1-subtag", ["aa-1", "aA"], None, "default-tag", None, "aA"), ( "Aa-P-subtag-8-subtag", ["Aa-p-subtag-8", "Aa-p", "aA"], None, "default-tag", None, "aA", ), ( "aA-3-subTag-C-subtag", ["aA-3-subtag-c", "aA-3", "aA"], None, "default-tag", None, "aA", ), # Test that single-letter or -digit subtag in first position works # as expected ( "T-subtag", ["t-SubTag", "another"], None, "default-tag", None, "t-SubTag", ), ("T-subtag", ["another"], None, "default-tag", None, "default-tag"), # If the language range "*" is followed by other language ranges, # it is skipped. ("*, Aa-aA-AA", ["bb", "aA"], None, "default-tag", None, "aA"), # If the language range "*" is the only one in the header, lookup # proceeds to the default arguments. ("*", ["bb", "aa"], None, "default-tag", None, "default-tag"), # If no other language range follows the "*" in the header, lookup # proceeds to the default arguments. ("dd, cc, *", ["bb", "aa"], None, "default-tag", None, "default-tag"), # If a non-'*' range has q=0, any tag that matches the range # exactly (without subtag truncation) is not acceptable. ( "aa, bB-Cc-DD;q=0, bB-Cc, cc", ["bb", "bb-Cc-DD", "bb-cC-dd", "Bb-cc", "bb-cC-dd"], None, "default-tag", None, "Bb-cc", ), # ;q=0 and ;q={not 0} both in header: q=0 takes precedence and # makes the exact match not acceptable, but the q={not 0} means # that tags can still match after subtag truncation. ( "aa, bB-Cc-DD;q=0.9, cc, Bb-cC-dD;q=0", ["bb", "Bb-Cc", "Bb-cC-dD"], None, "default-tag", None, "Bb-Cc", ), # If none of the ranges in the header match any of the language # tags, and the `default_range` argument is not None and does not # match any q=0 range in the header, we search through it by # progressively truncating from the end, as we do with the ranges # in the header. Example from RFC 4647, section 3.4.1: ( "fr-FR, zh-Hant", ["fr-FR", "fr", "zh-Hant", "zh", "ja-JP", "ja"], "ja-JP", "default-tag", None, "fr-FR", ), ( "fr-FR, zh-Hant", ["fr", "zh-Hant", "zh", "ja-JP", "ja"], "ja-JP", "default-tag", None, "fr", ), ( "fr-FR, zh-Hant", ["zh-Hant", "zh", "ja-JP", "ja"], "ja-JP", "default-tag", None, "zh-Hant", ), ( "fr-FR, zh-Hant", ["zh", "ja-JP", "ja"], "ja-JP", "default-tag", None, "zh", ), ("fr-FR, zh-Hant", ["ja-JP", "ja"], "ja-JP", "default-tag", None, "ja-JP"), ("fr-FR, zh-Hant", ["ja"], "ja-JP", "default-tag", None, "ja"), ( "fr-FR, zh-Hant", ["some-other-tag-1", "some-other-tag-2"], "ja-JP", "default-tag", None, "default-tag", ), # If none of the ranges in the header match the language tags, the # `default_range` argument is not None, and there is a '*;q=0' # range in the header, then the `default_range` and its substrings # from subtag truncation are not acceptable. ( "aa-bb, cc-dd, *;q=0", ["ee-ff", "ee"], "ee-ff", None, "default", "default", ), # If none of the ranges in the header match the language tags, the # `default_range` argument is not None, and the argument exactly # matches a non-'*' range in the header with q=0 (without fallback # subtag truncation), then the `default_range` itself is not # acceptable... ( "aa-bb, cc-dd, eE-Ff;q=0", ["Ee-fF"], "EE-FF", "default-tag", None, "default-tag", ), # ...but it should still be searched with subtag truncation, # because its substrings other than itself are still acceptable: ( "aa-bb, cc-dd, eE-Ff-Gg;q=0", ["Ee", "Ee-fF-gG", "Ee-fF"], "EE-FF-GG", "default-tag", None, "Ee-fF", ), ( "aa-bb, cc-dd, eE-Ff-Gg;q=0", ["Ee-fF-gG", "Ee"], "EE-FF-GG", "default-tag", None, "Ee", ), # If `default_range` only has one subtag, then no subtag truncation # is possible, and we proceed to `default-tag`: ("aa-bb, cc-dd, eE;q=0", ["Ee"], "EE", "default-tag", None, "default-tag"), # If the `default_range` argument would only match a non-'*' range # in the header with q=0 exactly if the `default_range` had subtags # from the end truncated, then it is acceptable, and we attempt to # match it with the language tags using subtag truncation. However, # the tag equivalent of the range with q=0 would be considered not # acceptable and ruled out, if we reach it during the subtag # truncation search. ( "aa-bb, cc-dd, eE-Ff;q=0", ["Ee-fF", "Ee-fF-33", "ee"], "EE-FF-33", "default-tag", None, "Ee-fF-33", ), ( "aa-bb, cc-dd, eE-Ff;q=0", ["Ee-fF", "eE"], "EE-FF-33", "default-tag", None, "eE", ), # If none of the ranges in the header match, the `default_range` # argument is None or does not match, and the `default_tag` # argument is not None and does not match any range in the header # with q=0, then the `default_tag` argument is returned. ("aa-bb, cc-dd", ["ee-ff", "ee"], None, "default-tag", None, "default-tag"), ( "aa-bb, cc-dd", ["ee-ff", "ee"], "gg-hh", "default-tag", None, "default-tag", ), # If none of the ranges in the header match, the `default_range` # argument is None or does not match, the `default_tag` argument is # not None, and there is a '*' range in the header with q=0, then # the `default_tag` argument is not acceptable. ( "aa-bb, cc-dd, *;q=0", ["ee-ff", "ee"], "gg-hh", "ii-jj", "default", "default", ), # If none of the ranges in the header match, the `default_range` # argument is None or does not match, the `default_tag` argument is # not None and matches a non-'*' range in the header with q=0 # exactly, then the `default_tag` argument is not acceptable. ( "aa-bb, cc-dd, iI-jJ;q=0", ["ee-ff", "ee"], "gg-hh", "Ii-Jj", "default", "default", ), # If none of the ranges in the header match, the `default_range` # argument is None or does not match, and the `default_tag` # argument is None, then we proceed to the `default` argument. ("aa-bb, cc-dd", ["ee-ff", "ee"], None, None, "default", "default"), ("aa-bb, cc-dd", ["ee-ff", "ee"], "gg-hh", None, "default", "default"), # If we fall back to the `default` argument, and it is not a # callable, the argument itself is returned. ("aa", ["bb"], None, None, 0, 0), ( "Aa, cC;q=0", ["bb"], "aA-Cc", "Cc", ["non-callable object"], ["non-callable object"], ), # If we fall back to the `default` argument, and it is a callable, # it is called, and the callable's return value is returned by the # method. ("aa", ["bb"], None, None, lambda: "callable called", "callable called"), ( "Aa, cc;q=0", ["bb"], "aA-cC", "cc", lambda: "callable called", "callable called", ), # Even if the 'default' argument is a str that matches a q=0 range # in the header, it is still returned. ("aa, *;q=0", ["bb"], None, None, "cc", "cc"), ("aa, cc;q=0", ["bb"], None, None, "cc", "cc"), # If the `default_tag` argument is not acceptable because of a q=0 # range in the header, and the `default` argument is None, then # None is returned. ("aa, Bb;q=0", ["cc"], None, "bB", None, None), ("aa, *;q=0", ["cc"], None, "bb", None, None), # Test that method works with empty `language_tags`: ("range", [], None, "default-tag", None, "default-tag"), # Test that method works with empty `default_range`: ("range", [], "", "default-tag", None, "default-tag"), ("range", ["tag"], "", "default-tag", None, "default-tag"), # Test that method works with empty `default_tag`: ("range", [], "", "", None, ""), ("range", ["tag"], "default-range", "", None, ""), ], ) def test_lookup( self, header_value, language_tags, default_range, default_tag, default, expected ): instance = AcceptLanguageValidHeader(header_value=header_value) returned = instance.lookup( language_tags=language_tags, default_range=default_range, default_tag=default_tag, default=default, ) assert returned == expected @pytest.mark.parametrize( "header_value, offer, expected_returned", [ ("en-gb", "en-gb", 1), ("en-gb;q=0.5", "en-gb", 0.5), ("en-gb", "sr-Cyrl", None), ], ) @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self, header_value, offer, expected_returned): instance = AcceptLanguageValidHeader(header_value=header_value) returned = instance.quality(offer=offer) assert returned == expected_returned class TestAcceptLanguageNoHeader: def test___init__(self): instance = AcceptLanguageNoHeader() assert instance.header_value is None assert instance.parsed is None assert instance._parsed_nonzero is None assert isinstance(instance, AcceptLanguage) def test___add___None(self): instance = AcceptLanguageNoHeader() result = instance + None assert isinstance(result, AcceptLanguageNoHeader) assert result is not instance @pytest.mark.parametrize( "right_operand", ["", [], (), {}, "en_gb", ["en_gb"], ("en_gb",), {"en_gb": 1.0}], ) def test___add___invalid_value(self, right_operand): left_operand = AcceptLanguageNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptLanguageNoHeader) assert result is not left_operand @pytest.mark.parametrize("str_", ["", "en_gb"]) def test___add___other_type_with_invalid___str__(self, str_): left_operand = AcceptLanguageNoHeader() class Other: def __str__(self): return str_ result = left_operand + Other() assert isinstance(result, AcceptLanguageNoHeader) assert result is not left_operand @pytest.mark.parametrize( "value, value_as_header", [ ("en-gb;q=0.5, fr;q=0, es", "en-gb;q=0.5, fr;q=0, es"), ([("en-gb", 0.5), ("fr", 0.0), "es"], "en-gb;q=0.5, fr;q=0, es"), ((("en-gb", 0.5), ("fr", 0.0), "es"), "en-gb;q=0.5, fr;q=0, es"), ({"en-gb": 0.5, "fr": 0.0, "es": 1.0}, "es, en-gb;q=0.5, fr;q=0"), ], ) def test___add___valid_value(self, value, value_as_header): result = AcceptLanguageNoHeader() + value assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == value_as_header def test___add___other_type_with_valid___str__(self): class Other: def __str__(self): return "en-gb;q=0.5, fr;q=0, es" right_operand = Other() result = AcceptLanguageNoHeader() + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == str(right_operand) def test___add___AcceptLanguageValidHeader(self): right_operand = AcceptLanguageValidHeader(header_value=", ,fr;q=0, \tes;q=1,") result = AcceptLanguageNoHeader() + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == right_operand.header_value def test___add___AcceptLanguageNoHeader(self): left_operand = AcceptLanguageNoHeader() right_operand = AcceptLanguageNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptLanguageNoHeader) assert result is not left_operand assert result is not right_operand @pytest.mark.parametrize("invalid_header_value", ["", "en_gb"]) def test___add___AcceptLanguageInvalidHeader(self, invalid_header_value): left_operand = AcceptLanguageNoHeader() result = left_operand + AcceptLanguageInvalidHeader( header_value=invalid_header_value ) assert isinstance(result, AcceptLanguageNoHeader) assert result is not left_operand def test___bool__(self): instance = AcceptLanguageNoHeader() returned = bool(instance) assert returned is False @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): instance = AcceptLanguageNoHeader() returned = "any-tag" in instance assert returned is True @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptLanguageNoHeader() returned = list(instance) assert returned == [] def test___radd___None(self): right_operand = AcceptLanguageNoHeader() result = None + right_operand assert isinstance(result, AcceptLanguageNoHeader) assert result is not right_operand @pytest.mark.parametrize( "left_operand", ["", [], (), {}, "en_gb", ["en_gb"], ("en_gb",), {"en_gb": 1.0}] ) def test___radd___invalid_value(self, left_operand): right_operand = AcceptLanguageNoHeader() result = left_operand + right_operand assert isinstance(result, AcceptLanguageNoHeader) assert result is not right_operand @pytest.mark.parametrize("str_", ["", "en_gb", ","]) def test___radd___other_type_with_invalid___str__(self, str_): right_operand = AcceptLanguageNoHeader() class Other: def __str__(self): return str_ result = Other() + right_operand assert isinstance(result, AcceptLanguageNoHeader) assert result is not right_operand @pytest.mark.parametrize( "value, value_as_header", [ ("en-gb;q=0.5, fr;q=0, es", "en-gb;q=0.5, fr;q=0, es"), ([("en-gb", 0.5), ("fr", 0.0), "es"], "en-gb;q=0.5, fr;q=0, es"), ((("en-gb", 0.5), ("fr", 0.0), "es"), "en-gb;q=0.5, fr;q=0, es"), ({"en-gb": 0.5, "fr": 0.0, "es": 1.0}, "es, en-gb;q=0.5, fr;q=0"), ], ) def test___radd___valid_value(self, value, value_as_header): result = value + AcceptLanguageNoHeader() assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == value_as_header def test___radd___other_type_with_valid___str__(self): class Other: def __str__(self): return "en-gb;q=0.5, fr;q=0, es" left_operand = Other() result = left_operand + AcceptLanguageNoHeader() assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == str(left_operand) def test___repr__(self): instance = AcceptLanguageNoHeader() assert repr(instance) == "" def test___str__(self): instance = AcceptLanguageNoHeader() assert str(instance) == "" def test_basic_filtering(self): instance = AcceptLanguageNoHeader() returned = instance.basic_filtering(language_tags=["tag1", "tag2"]) assert returned == [] @pytest.mark.parametrize( "offers, default_match, expected_returned", [ (["foo", "bar"], None, "foo"), ([("foo", 1), ("bar", 0.5)], None, "foo"), ([("foo", 0.5), ("bar", 1)], None, "bar"), ([("foo", 0.5), "bar"], None, "bar"), ([("foo", 0.5), "bar"], object(), "bar"), ([], "fallback", "fallback"), ], ) @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self, offers, default_match, expected_returned): instance = AcceptLanguageNoHeader() returned = instance.best_match(offers=offers, default_match=default_match) assert returned == expected_returned def test_lookup_default_tag_and_default_cannot_both_be_None(self): instance = AcceptLanguageNoHeader() with pytest.raises(TypeError): instance.lookup(default_tag=None, default=None) @pytest.mark.parametrize( "default_tag, default, expected", [ # If `default_tag` is not None, it is returned. ("default-tag", "default", "default-tag"), # If `default_tag` is None, we proceed to the `default` argument. If # `default` is not a callable, the argument itself is returned. (None, 0, 0), # If `default` is a callable, it is called, and the callable's return # value is returned by the method. (None, lambda: "callable called", "callable called"), ], ) def test_lookup(self, default_tag, default, expected): instance = AcceptLanguageNoHeader() returned = instance.lookup(default_tag=default_tag, default=default) assert returned == expected @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): instance = AcceptLanguageNoHeader() returned = instance.quality(offer="any-tag") assert returned == 1.0 class TestAcceptLanguageInvalidHeader: def test___init__(self): header_value = "invalid header" instance = AcceptLanguageInvalidHeader(header_value=header_value) assert instance.header_value == header_value assert instance.parsed is None assert instance._parsed_nonzero is None assert isinstance(instance, AcceptLanguage) def test___add___None(self): instance = AcceptLanguageInvalidHeader(header_value="") result = instance + None assert isinstance(result, AcceptLanguageNoHeader) @pytest.mark.parametrize( "right_operand", ["", [], (), {}, "en_gb", ["en_gb"], ("en_gb",), {"en_gb": 1.0}], ) def test___add___invalid_value(self, right_operand): result = AcceptLanguageInvalidHeader(header_value="") + right_operand assert isinstance(result, AcceptLanguageNoHeader) @pytest.mark.parametrize("str_", ["", "en_gb"]) def test___add___other_type_with_invalid___str__(self, str_): class Other: def __str__(self): return str_ result = AcceptLanguageInvalidHeader(header_value="") + Other() assert isinstance(result, AcceptLanguageNoHeader) @pytest.mark.parametrize("value", ["en", ["en"], ("en",), {"en": 1.0}]) def test___add___valid_header_value(self, value): result = AcceptLanguageInvalidHeader(header_value="") + value assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == "en" def test___add___other_type_valid_header_value(self): class Other: def __str__(self): return "en" result = AcceptLanguageInvalidHeader(header_value="") + Other() assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == "en" def test___add___AcceptLanguageValidHeader(self): right_operand = AcceptLanguageValidHeader(header_value="en") result = AcceptLanguageInvalidHeader(header_value="") + right_operand assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == right_operand.header_value assert result is not right_operand def test___add___AcceptLanguageNoHeader(self): right_operand = AcceptLanguageNoHeader() result = AcceptLanguageInvalidHeader(header_value="") + right_operand assert isinstance(result, AcceptLanguageNoHeader) assert result is not right_operand def test___add___AcceptLanguageInvalidHeader(self): result = AcceptLanguageInvalidHeader( header_value="" ) + AcceptLanguageInvalidHeader(header_value="") assert isinstance(result, AcceptLanguageNoHeader) def test___bool__(self): instance = AcceptLanguageInvalidHeader(header_value="") returned = bool(instance) assert returned is False @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test___contains__(self): instance = AcceptLanguageInvalidHeader(header_value="") returned = "any-tag" in instance assert returned is True @pytest.mark.filterwarnings(IGNORE_ITER) def test___iter__(self): instance = AcceptLanguageInvalidHeader(header_value="") returned = list(instance) assert returned == [] def test___radd___None(self): instance = AcceptLanguageInvalidHeader(header_value="") result = None + instance assert isinstance(result, AcceptLanguageNoHeader) @pytest.mark.parametrize( "left_operand", ["", [], (), {}, "en_gb", ["en_gb"], ("en_gb",), {"en_gb": 1.0}] ) def test___radd___invalid_value(self, left_operand): result = left_operand + AcceptLanguageInvalidHeader(header_value="") assert isinstance(result, AcceptLanguageNoHeader) @pytest.mark.parametrize("str_", ["", "en_gb"]) def test___radd___other_type_with_invalid___str__(self, str_): class Other: def __str__(self): return str_ result = Other() + AcceptLanguageInvalidHeader(header_value="") assert isinstance(result, AcceptLanguageNoHeader) @pytest.mark.parametrize("value", ["en", ["en"], ("en",), {"en": 1.0}]) def test___radd___valid_header_value(self, value): result = value + AcceptLanguageInvalidHeader(header_value="") assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == "en" def test___radd___other_type_valid_header_value(self): class Other: def __str__(self): return "en" result = Other() + AcceptLanguageInvalidHeader(header_value="") assert isinstance(result, AcceptLanguageValidHeader) assert result.header_value == "en" def test___repr__(self): instance = AcceptLanguageInvalidHeader(header_value="\x00") assert repr(instance) == "" def test___str__(self): instance = AcceptLanguageInvalidHeader(header_value="invalid header") assert str(instance) == "" def test_basic_filtering(self): instance = AcceptLanguageInvalidHeader(header_value="") returned = instance.basic_filtering(language_tags=["tag1", "tag2"]) assert returned == [] @pytest.mark.parametrize( "offers, default_match, expected_returned", [ (["foo", "bar"], None, "foo"), ([("foo", 1), ("bar", 0.5)], None, "foo"), ([("foo", 0.5), ("bar", 1)], None, "bar"), ([("foo", 0.5), "bar"], None, "bar"), ([("foo", 0.5), "bar"], object(), "bar"), ([], "fallback", "fallback"), ], ) @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_best_match(self, offers, default_match, expected_returned): instance = AcceptLanguageInvalidHeader(header_value="") returned = instance.best_match(offers=offers, default_match=default_match) assert returned == expected_returned def test_lookup_default_tag_and_default_cannot_both_be_None(self): instance = AcceptLanguageInvalidHeader(header_value="") with pytest.raises(TypeError): instance.lookup(default_tag=None, default=None) @pytest.mark.parametrize( "default_tag, default, expected", [ # If `default_tag` is not None, it is returned. ("default-tag", "default", "default-tag"), # If `default_tag` is None, we proceed to the `default` argument. If # `default` is not a callable, the argument itself is returned. (None, 0, 0), # If `default` is a callable, it is called, and the callable's return # value is returned by the method. (None, lambda: "callable called", "callable called"), ], ) def test_lookup(self, default_tag, default, expected): instance = AcceptLanguageInvalidHeader(header_value="") returned = instance.lookup(default_tag=default_tag, default=default) assert returned == expected @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_quality(self): instance = AcceptLanguageInvalidHeader(header_value="") returned = instance.quality(offer="any-tag") assert returned == 1.0 class TestCreateAcceptLanguageHeader: def test_header_value_is_None(self): header_value = None returned = create_accept_language_header(header_value=header_value) assert isinstance(returned, AcceptLanguageNoHeader) assert returned.header_value == header_value returned2 = create_accept_language_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value def test_header_value_is_valid(self): header_value = "es, ja" returned = create_accept_language_header(header_value=header_value) assert isinstance(returned, AcceptLanguageValidHeader) assert returned.header_value == header_value returned2 = create_accept_language_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value @pytest.mark.parametrize("header_value", ["", "en_gb"]) def test_header_value_is_invalid(self, header_value): returned = create_accept_language_header(header_value=header_value) assert isinstance(returned, AcceptLanguageInvalidHeader) assert returned.header_value == header_value returned2 = create_accept_language_header(returned) assert returned2 is not returned assert returned2._header_value == returned._header_value class TestAcceptLanguageProperty: def test_fget_header_is_None(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": None}) property_ = accept_language_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptLanguageNoHeader) def test_fget_header_is_valid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": "es"}) property_ = accept_language_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptLanguageValidHeader) def test_fget_header_is_invalid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": "en_gb"}) property_ = accept_language_property() returned = property_.fget(request=request) assert isinstance(returned, AcceptLanguageInvalidHeader) def test_fset_value_is_None(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": "es"}) property_ = accept_language_property() property_.fset(request=request, value=None) assert isinstance(request.accept_language, AcceptLanguageNoHeader) assert "HTTP_ACCEPT_LANGUAGE" not in request.environ def test_fset_value_is_invalid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": "es"}) property_ = accept_language_property() property_.fset(request=request, value="en_GB") assert isinstance(request.accept_language, AcceptLanguageInvalidHeader) assert request.environ["HTTP_ACCEPT_LANGUAGE"] == "en_GB" def test_fset_value_is_valid(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": "es"}) property_ = accept_language_property() property_.fset(request=request, value="en-GB") assert isinstance(request.accept_language, AcceptLanguageValidHeader) assert request.environ["HTTP_ACCEPT_LANGUAGE"] == "en-GB" @pytest.mark.parametrize( "value, value_as_header", [ ("en-gb;q=0.5, fr;q=0, es", "en-gb;q=0.5, fr;q=0, es"), ([("en-gb", 0.5), ("fr", 0.0), "es"], "en-gb;q=0.5, fr;q=0, es"), ((("en-gb", 0.5), ("fr", 0.0), "es"), "en-gb;q=0.5, fr;q=0, es"), ({"en-gb": 0.5, "fr": 0.0, "es": 1.0}, "es, en-gb;q=0.5, fr;q=0"), ], ) def test_fset_value_types(self, value, value_as_header): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": ""}) property_ = accept_language_property() property_.fset(request=request, value=value) assert isinstance(request.accept_language, AcceptLanguageValidHeader) assert request.environ["HTTP_ACCEPT_LANGUAGE"] == value_as_header def test_fset_other_type_with_valid___str__(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": ""}) property_ = accept_language_property() class Other: def __str__(self): return "en-gb;q=0.5, fr;q=0, es" value = Other() property_.fset(request=request, value=value) assert isinstance(request.accept_language, AcceptLanguageValidHeader) assert request.environ["HTTP_ACCEPT_LANGUAGE"] == str(value) def test_fset_AcceptLanguageNoHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": "en"}) property_ = accept_language_property() header = AcceptLanguageNoHeader() property_.fset(request=request, value=header) assert isinstance(request.accept_language, AcceptLanguageNoHeader) assert "HTTP_ACCEPT_LANGUAGE" not in request.environ def test_fset_AcceptLanguageValidHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": ""}) property_ = accept_language_property() header = AcceptLanguageValidHeader("es") property_.fset(request=request, value=header) assert isinstance(request.accept_language, AcceptLanguageValidHeader) assert request.environ["HTTP_ACCEPT_LANGUAGE"] == header.header_value def test_fset_AcceptLanguageInvalidHeader(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": ""}) property_ = accept_language_property() header = AcceptLanguageInvalidHeader("en_gb") property_.fset(request=request, value=header) assert isinstance(request.accept_language, AcceptLanguageInvalidHeader) assert request.environ["HTTP_ACCEPT_LANGUAGE"] == header.header_value def test_fdel_header_key_in_environ(self): request = Request.blank("/", environ={"HTTP_ACCEPT_LANGUAGE": "es"}) property_ = accept_language_property() property_.fdel(request=request) assert isinstance(request.accept_language, AcceptLanguageNoHeader) assert "HTTP_ACCEPT_LANGUAGE" not in request.environ def test_fdel_header_key_not_in_environ(self): request = Request.blank("/") property_ = accept_language_property() property_.fdel(request=request) assert isinstance(request.accept_language, AcceptLanguageNoHeader) assert "HTTP_ACCEPT_LANGUAGE" not in request.environ # Deprecated tests: @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) def test_MIMEAccept_init_warns(): with warnings.catch_warnings(record=True) as warning: warnings.simplefilter("always") MIMEAccept("image/jpg") assert len(warning) == 1 @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) def test_MIMEAccept_init(): mimeaccept = MIMEAccept("image/jpg") assert mimeaccept._parsed == [("image/jpg", 1)] mimeaccept = MIMEAccept("image/png, image/jpg;q=0.5") assert mimeaccept._parsed == [("image/png", 1), ("image/jpg", 0.5)] mimeaccept = MIMEAccept("image, image/jpg;q=0.5") assert mimeaccept._parsed == [] mimeaccept = MIMEAccept("*/*") assert mimeaccept._parsed == [("*/*", 1)] mimeaccept = MIMEAccept("*/png") assert mimeaccept._parsed == [("*/png", 1)] mimeaccept = MIMEAccept("image/pn*") assert mimeaccept._parsed == [("image/pn*", 1.0)] mimeaccept = MIMEAccept("image/*") assert mimeaccept._parsed == [("image/*", 1)] @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test_MIMEAccept_parse(): assert list(MIMEAccept.parse("image/jpg")) == [("image/jpg", 1)] assert list(MIMEAccept.parse("invalid")) == [] @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) def test_MIMEAccept_accept_html(): mimeaccept = MIMEAccept("image/jpg") assert not mimeaccept.accept_html() mimeaccept = MIMEAccept("image/jpg, text/html") assert mimeaccept.accept_html() @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test_MIMEAccept_contains(): mimeaccept = MIMEAccept("A/a, B/b, C/c") assert "A/a" in mimeaccept assert "A/*" in mimeaccept assert "*/a" in mimeaccept assert "A/b" not in mimeaccept assert "B/a" not in mimeaccept @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) @pytest.mark.filterwarnings(IGNORE_BEST_MATCH) def test_MIMEAccept_json(): mimeaccept = MIMEAccept("text/html, */*; q=.2") assert mimeaccept.best_match(["application/json"]) == "application/json" @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) def test_MIMEAccept_no_raise_invalid(): assert MIMEAccept("invalid") @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) @pytest.mark.filterwarnings(IGNORE_ITER) def test_MIMEAccept_iter(): assert list(iter(MIMEAccept("text/html, other/whatever"))) == [ "text/html", "other/whatever", ] @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) def test_MIMEAccept_str(): assert str(MIMEAccept("image/jpg")) == "image/jpg" @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) def test_MIMEAccept_add(): assert str(MIMEAccept("image/jpg") + "image/png") == "image/jpg, image/png" assert ( str(MIMEAccept("image/jpg") + MIMEAccept("image/png")) == "image/jpg, image/png" ) assert isinstance(MIMEAccept("image/jpg") + "image/png", MIMEAccept) assert isinstance(MIMEAccept("image/jpg") + MIMEAccept("image/png"), MIMEAccept) @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) def test_MIMEAccept_radd(): assert str("image/png" + MIMEAccept("image/jpg")) == "image/png, image/jpg" assert isinstance("image/png" + MIMEAccept("image/jpg"), MIMEAccept) @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) @pytest.mark.filterwarnings(IGNORE_CONTAINS) def test_MIMEAccept_repr(): assert "image/jpg" in repr(MIMEAccept("image/jpg")) @pytest.mark.filterwarnings(IGNORE_MIMEACCEPT) @pytest.mark.filterwarnings(IGNORE_QUALITY) def test_MIMEAccept_quality(): assert MIMEAccept("image/jpg;q=0.9").quality("image/jpg") == 0.9 assert MIMEAccept("image/png;q=0.9").quality("image/jpg") is None