# -*- 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)