# -*- coding: utf-8 -*- """Tests for the validators module.""" import rfc3986 from rfc3986 import exceptions from rfc3986 import validators import pytest def test_defaults(): """Verify the default Validator settings.""" validator = validators.Validator() assert validator.required_components == { c: False for c in validator.COMPONENT_NAMES } assert validator.allow_password is True assert validator.allowed_schemes == set() assert validator.allowed_hosts == set() assert validator.allowed_ports == set() def test_allowing_schemes(): """Verify the ability to select schemes to be allowed.""" validator = validators.Validator().allow_schemes("http", "https") assert "http" in validator.allowed_schemes assert "https" in validator.allowed_schemes def test_allowing_hosts(): """Verify the ability to select hosts to be allowed.""" validator = validators.Validator().allow_hosts( "pypi.python.org", "pypi.org", ) assert "pypi.python.org" in validator.allowed_hosts assert "pypi.org" in validator.allowed_hosts def test_allowing_ports(): """Verify the ability select ports to be allowed.""" validator = validators.Validator().allow_ports("80", "100") assert "80" in validator.allowed_ports assert "100" in validator.allowed_ports def test_requiring_invalid_component(): """Verify that we validate required component names.""" with pytest.raises(ValueError): validators.Validator().require_presence_of("frob") def test_checking_validity_of_component(): """Verify that we validate components we're validating.""" with pytest.raises(ValueError): validators.Validator().check_validity_of("frob") def test_use_of_password(): """Verify the behaviour of {forbid,allow}_use_of_password.""" validator = validators.Validator() assert validator.allow_password is True validator.forbid_use_of_password() assert validator.allow_password is False validator.allow_use_of_password() assert validator.allow_password is True @pytest.mark.parametrize( "uri", [ rfc3986.uri_reference("https://user:password@github.com"), rfc3986.uri_reference("https://user:password@github.com/path"), rfc3986.uri_reference("https://user:password@github.com/path?query"), rfc3986.uri_reference( "https://user:password@github.com/path?query#frag" ), rfc3986.uri_reference("//user:password@github.com"), ], ) def test_forbidden_passwords(uri): """Verify that passwords are disallowed.""" validator = validators.Validator().forbid_use_of_password() with pytest.raises(exceptions.PasswordForbidden): validator.validate(uri) @pytest.mark.parametrize( "uri", [ rfc3986.uri_reference("https://user@github.com"), rfc3986.uri_reference("https://user@github.com/path"), rfc3986.uri_reference("https://user@github.com/path?query"), rfc3986.uri_reference("https://user@github.com/path?query#frag"), rfc3986.uri_reference("//user@github.com"), rfc3986.uri_reference("//github.com"), rfc3986.uri_reference("https://github.com"), ], ) def test_passwordless_uris_pass_validation(uri): """Verify password-less URLs validate properly.""" validator = validators.Validator().forbid_use_of_password() validator.validate(uri) @pytest.mark.parametrize( "uri", [ rfc3986.uri_reference("https://"), rfc3986.uri_reference("/path/to/resource"), ], ) def test_missing_host_component(uri): """Verify that missing host components cause errors.""" validators.Validator().validate(uri) validator = validators.Validator().require_presence_of("host") with pytest.raises(exceptions.MissingComponentError): validator.validate(uri) @pytest.mark.parametrize( "uri", [ rfc3986.uri_reference("https://"), rfc3986.uri_reference("//google.com"), rfc3986.uri_reference("//google.com?query=value"), rfc3986.uri_reference("//google.com#fragment"), rfc3986.uri_reference("https://google.com"), rfc3986.uri_reference("https://google.com#fragment"), rfc3986.uri_reference("https://google.com?query=value"), ], ) def test_missing_path_component(uri): """Verify that missing path components cause errors.""" validator = validators.Validator().require_presence_of("path") with pytest.raises(exceptions.MissingComponentError): validator.validate(uri) @pytest.mark.parametrize( "uri", [ rfc3986.uri_reference("//google.com"), rfc3986.uri_reference("//google.com?query=value"), rfc3986.uri_reference("//google.com#fragment"), ], ) def test_multiple_missing_components(uri): """Verify that multiple missing components are caught.""" validator = validators.Validator().require_presence_of("scheme", "path") with pytest.raises(exceptions.MissingComponentError) as captured_exc: validator.validate(uri) exception = captured_exc.value assert 2 == len(exception.args[-1]) @pytest.mark.parametrize( "uri", [ rfc3986.uri_reference("smtp://"), rfc3986.uri_reference("telnet://"), ], ) def test_ensure_uri_has_a_scheme(uri): """Verify validation with allowed schemes.""" validator = validators.Validator().allow_schemes("https", "http") with pytest.raises(exceptions.UnpermittedComponentError): validator.validate(uri) @pytest.mark.parametrize( "uri, failed_component", [ (rfc3986.uri_reference("git://github.com"), "scheme"), (rfc3986.uri_reference("http://github.com"), "scheme"), (rfc3986.uri_reference("ssh://gitlab.com"), "host"), (rfc3986.uri_reference("https://gitlab.com"), "host"), ], ) def test_allowed_hosts_and_schemes(uri, failed_component): """Verify each of these fails.""" validator = ( validators.Validator() .allow_schemes( "https", "ssh", ) .allow_hosts( "github.com", "git.openstack.org", ) ) with pytest.raises(exceptions.UnpermittedComponentError) as caught_exc: validator.validate(uri) exc = caught_exc.value assert exc.component_name == failed_component @pytest.mark.parametrize( "uri", [ rfc3986.uri_reference("https://github.com/sigmavirus24"), rfc3986.uri_reference("ssh://github.com/sigmavirus24"), rfc3986.uri_reference("ssh://ssh@github.com:22/sigmavirus24"), rfc3986.uri_reference("https://github.com:443/sigmavirus24"), rfc3986.uri_reference("https://gitlab.com/sigmavirus24"), rfc3986.uri_reference("ssh://gitlab.com/sigmavirus24"), rfc3986.uri_reference("ssh://ssh@gitlab.com:22/sigmavirus24"), rfc3986.uri_reference("https://gitlab.com:443/sigmavirus24"), rfc3986.uri_reference("https://bitbucket.org/sigmavirus24"), rfc3986.uri_reference("ssh://bitbucket.org/sigmavirus24"), rfc3986.uri_reference("ssh://ssh@bitbucket.org:22/sigmavirus24"), rfc3986.uri_reference("https://bitbucket.org:443/sigmavirus24"), rfc3986.uri_reference("https://git.openstack.org/sigmavirus24"), rfc3986.uri_reference("ssh://git.openstack.org/sigmavirus24"), rfc3986.uri_reference("ssh://ssh@git.openstack.org:22/sigmavirus24"), rfc3986.uri_reference("https://git.openstack.org:443/sigmavirus24"), rfc3986.uri_reference( "ssh://ssh@git.openstack.org:22/sigmavirus24?foo=bar#fragment" ), rfc3986.uri_reference( "ssh://git.openstack.org:22/sigmavirus24?foo=bar#fragment" ), rfc3986.uri_reference("ssh://git.openstack.org:22/?foo=bar#fragment"), rfc3986.uri_reference( "ssh://git.openstack.org:22/sigmavirus24#fragment" ), rfc3986.uri_reference("ssh://git.openstack.org:22/#fragment"), rfc3986.uri_reference("ssh://git.openstack.org:22/"), rfc3986.uri_reference( "ssh://ssh@git.openstack.org:22/?foo=bar#fragment" ), rfc3986.uri_reference( "ssh://ssh@git.openstack.org:22/sigmavirus24#fragment" ), rfc3986.uri_reference("ssh://ssh@git.openstack.org:22/#fragment"), rfc3986.uri_reference("ssh://ssh@git.openstack.org:22/"), ], ) def test_successful_complex_validation(uri): """Verify we do not raise ValidationErrors for good URIs.""" validators.Validator().allow_schemes("https", "ssh",).allow_hosts( "github.com", "bitbucket.org", "gitlab.com", "git.openstack.org", ).allow_ports("22", "443",).require_presence_of( "scheme", "host", "path", ).check_validity_of( "scheme", "userinfo", "host", "port", "path", "query", "fragment", ).validate( uri ) def test_invalid_uri_generates_error(invalid_uri): """Verify we catch invalid URIs.""" uri = rfc3986.uri_reference(invalid_uri) with pytest.raises(exceptions.InvalidComponentsError): validators.Validator().check_validity_of("host").validate(uri) def test_invalid_uri_with_invalid_path(invalid_uri): """Verify we catch multiple invalid components.""" uri = rfc3986.uri_reference(invalid_uri) uri = uri.copy_with(path="#foobar") with pytest.raises(exceptions.InvalidComponentsError): validators.Validator().check_validity_of( "host", "path", ).validate(uri) def test_validating_rfc_4007_ipv6_zone_ids(): """Verify that RFC 4007 IPv6 Zone IDs are invalid host/authority but after normalization are valid """ uri = rfc3986.uri_reference("http://[::1%eth0]") with pytest.raises(exceptions.InvalidComponentsError): validators.Validator().check_validity_of("host").validate(uri) uri = uri.normalize() assert uri.host == "[::1%25eth0]" validators.Validator().check_validity_of("host").validate(uri)