# -*- coding: utf-8 -*- # Copyright (c) 2017 Ian Stapleton Cordasco # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. """Module containing the tests for the URIBuilder object.""" try: from urllib.parse import parse_qs except ImportError: from urlparse import parse_qs import pytest import rfc3986.builder as builder from rfc3986.api import uri_reference def test_builder_default(): """Verify the default values.""" uribuilder = builder.URIBuilder() assert uribuilder.scheme is None assert uribuilder.userinfo is None assert uribuilder.host is None assert uribuilder.port is None assert uribuilder.path is None assert uribuilder.query is None assert uribuilder.fragment is None def test_from_uri_reference(): uri = uri_reference("http://foo.bar:1234/baz") uribuilder = builder.URIBuilder().from_uri(uri) assert uribuilder.scheme == "http" assert uribuilder.userinfo is None assert uribuilder.host == "foo.bar" assert uribuilder.port == "1234" assert uribuilder.path == "/baz" assert uribuilder.query is None assert uribuilder.fragment is None def test_from_uri_string(): uribuilder = builder.URIBuilder().from_uri("https://bar.foo:4321/boom") assert uribuilder.scheme == "https" assert uribuilder.userinfo is None assert uribuilder.host == "bar.foo" assert uribuilder.port == "4321" assert uribuilder.path == "/boom" assert uribuilder.query is None assert uribuilder.fragment is None def test_repr(): """Verify our repr looks like our class.""" uribuilder = builder.URIBuilder() assert repr(uribuilder).startswith("URIBuilder(scheme=None") @pytest.mark.parametrize( "scheme", [ "https", "hTTps", "Https", "HtTpS", "HTTPS", ], ) def test_add_scheme(scheme): """Verify schemes are normalized when added.""" uribuilder = builder.URIBuilder().add_scheme(scheme) assert uribuilder.scheme == "https" @pytest.mark.parametrize( "username, password, userinfo", [ ("user", "pass", "user:pass"), ("user", None, "user"), ("user@domain.com", "password", "user%40domain.com:password"), ("user", "pass:word", "user:pass%3Aword"), ], ) def test_add_credentials(username, password, userinfo): """Verify we normalize usernames and passwords.""" uribuilder = builder.URIBuilder().add_credentials(username, password) assert uribuilder.userinfo == userinfo def test_add_credentials_requires_username(): """Verify one needs a username to add credentials.""" with pytest.raises(ValueError): builder.URIBuilder().add_credentials(None, None) @pytest.mark.parametrize( ["hostname", "expected_hostname"], [ ("google.com", "google.com"), ("GOOGLE.COM", "google.com"), ("gOOgLe.COM", "google.com"), ("goOgLE.com", "google.com"), ("[::ff%etH0]", "[::ff%25etH0]"), ("[::ff%25etH0]", "[::ff%25etH0]"), ("[::FF%etH0]", "[::ff%25etH0]"), ], ) def test_add_host(hostname, expected_hostname): """Verify we normalize hostnames in add_host.""" uribuilder = builder.URIBuilder().add_host(hostname) assert uribuilder.host == expected_hostname @pytest.mark.parametrize( "port", [ -100, "-100", -1, "-1", 65536, "65536", 1000000, "1000000", "", "abc", "0b10", ], ) def test_add_invalid_port(port): """Verify we raise a ValueError for invalid ports.""" with pytest.raises(ValueError): builder.URIBuilder().add_port(port) @pytest.mark.parametrize( "port, expected", [ (0, "0"), ("0", "0"), (1, "1"), ("1", "1"), (22, "22"), ("22", "22"), (80, "80"), ("80", "80"), (443, "443"), ("443", "443"), (65535, "65535"), ("65535", "65535"), ], ) def test_add_port(port, expected): """Verify we normalize our port.""" uribuilder = builder.URIBuilder().add_port(port) assert uribuilder.port == expected @pytest.mark.parametrize( "path", [ "sigmavirus24/rfc3986", "/sigmavirus24/rfc3986", ], ) def test_add_path(path): """Verify we normalize our path value.""" uribuilder = builder.URIBuilder().add_path(path) assert uribuilder.path == "/sigmavirus24/rfc3986" @pytest.mark.parametrize( "query_items, expected", [ ({"a": "b c"}, "a=b+c"), ({"a": "b+c"}, "a=b%2Bc"), ([("a", "b c")], "a=b+c"), ([("a", "b+c")], "a=b%2Bc"), ([("a", "b"), ("c", "d")], "a=b&c=d"), ([("a", "b"), ("username", "@d")], "a=b&username=%40d"), ([("percent", "%")], "percent=%25"), ], ) def test_add_query_from(query_items, expected): """Verify the behaviour of add_query_from.""" uribuilder = builder.URIBuilder().add_query_from(query_items) assert uribuilder.query == expected def test_add_query(): """Verify we do not modify the provided query string.""" uribuilder = builder.URIBuilder().add_query("username=@foo") assert uribuilder.query == "username=@foo" def test_add_fragment(): """Verify our handling of fragments.""" uribuilder = builder.URIBuilder().add_fragment("section-2.5.1") assert uribuilder.fragment == "section-2.5.1" @pytest.mark.parametrize( "uri, extend_with, expected_path", [ ("https://api.github.com", "/users", "/users"), ("https://api.github.com", "/users/", "/users/"), ("https://api.github.com", "users", "/users"), ("https://api.github.com", "users/", "/users/"), ("", "users/", "/users/"), ("", "users", "/users"), ("?foo=bar", "users", "/users"), ( "https://api.github.com/users/", "sigmavirus24", "/users/sigmavirus24", ), ( "https://api.github.com/users", "sigmavirus24", "/users/sigmavirus24", ), ( "https://api.github.com/users", "/sigmavirus24", "/users/sigmavirus24", ), ], ) def test_extend_path(uri, extend_with, expected_path): """Verify the behaviour of extend_path.""" uribuilder = ( builder.URIBuilder() .from_uri(uri_reference(uri)) .extend_path(extend_with) ) assert uribuilder.path == expected_path @pytest.mark.parametrize( "uri, extend_with, expected_query", [ ( "https://github.com", [("a", "b c"), ("d", "e&f")], {"a": ["b c"], "d": ["e&f"]}, ), ( "https://github.com?a=0", [("a", "b c"), ("d", "e&f")], {"a": ["0", "b c"], "d": ["e&f"]}, ), ( "https://github.com?a=0&e=f", [("a", "b c"), ("d", "e&f")], {"a": ["0", "b c"], "e": ["f"], "d": ["e&f"]}, ), ( "https://github.com", {"a": "b c", "d": "e&f"}, {"a": ["b c"], "d": ["e&f"]}, ), ( "https://github.com?a=0", {"a": "b c", "d": "e&f"}, {"a": ["0", "b c"], "d": ["e&f"]}, ), ( "https://github.com?a=0&e=f", {"a": "b c", "d": "e&f"}, {"a": ["0", "b c"], "e": ["f"], "d": ["e&f"]}, ), ], ) def test_extend_query_with(uri, extend_with, expected_query): """Verify the behaviour of extend_query_with.""" uribuilder = ( builder.URIBuilder() .from_uri(uri_reference(uri)) .extend_query_with(extend_with) ) assert parse_qs(uribuilder.query) == expected_query def test_finalize(): """Verify the whole thing.""" uri = ( builder.URIBuilder() .add_scheme("https") .add_credentials("sigmavirus24", "not-my-re@l-password") .add_host("github.com") .add_path("sigmavirus24/rfc3986") .finalize() .unsplit() ) expected = ( "https://sigmavirus24:not-my-re%40l-password@github.com/" "sigmavirus24/rfc3986" ) assert expected == uri def test_geturl(): """Verify the short-cut to the URL.""" uri = ( builder.URIBuilder() .add_scheme("https") .add_credentials("sigmavirus24", "not-my-re@l-password") .add_host("github.com") .add_path("sigmavirus24/rfc3986") .geturl() ) expected = ( "https://sigmavirus24:not-my-re%40l-password@github.com/" "sigmavirus24/rfc3986" ) assert expected == uri