Add tests and fix bugs found while testing

This commit is contained in:
Ian Cordasco
2015-07-04 21:07:54 -05:00
parent 6bfc998acb
commit d077c8f05b
8 changed files with 288 additions and 187 deletions

View File

@@ -83,12 +83,7 @@ class ParseResult(namedtuple('ParseResult', PARSED_COMPONENTS)):
@property
def authority(self):
"""Normalized authority generated from the subauthority parts."""
_authority = getattr(self, '_authority', None)
if _authority is None:
_authority = self._authority = normalizers.normalize_authority(
(self.userinfo, self.host, self.port)
)
return _authority
return self.reference.authority
def _generate_authority(self, attributes):
# I swear I did not align the comparisons below. That's just how they
@@ -98,6 +93,8 @@ class ParseResult(namedtuple('ParseResult', PARSED_COMPONENTS)):
if (self.userinfo != userinfo or
self.host != host or
self.port != port):
if port:
port = '{0}'.format(port)
return normalizers.normalize_authority((userinfo, host, port))
return self.authority
@@ -165,6 +162,7 @@ def split_authority(authority):
# Handle IPv6 host addresses
if rest.startswith(u'['):
host, rest = rest.split(u']', 1)
host += u']'
if ':' in rest:
extra_host, port = rest.split(u':', 1)

0
tests/__init__.py Normal file
View File

140
tests/base.py Normal file
View File

@@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015 Ian 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.
class BaseTestParsesURIs:
test_class = None
"""Tests for self.test_class handling of URIs."""
def test_handles_basic_uri(self, basic_uri):
"""Test that self.test_class can handle a simple URI."""
uri = self.test_class.from_string(basic_uri)
assert uri.scheme == 'http'
assert uri.authority == basic_uri[7:] # len('http://')
assert uri.host == uri.authority
assert uri.path is None
assert uri.query is None
assert uri.fragment is None
assert uri.port is None
assert uri.userinfo is None
def test_handles_basic_uri_with_port(self, basic_uri_with_port):
"""Test that self.test_class can handle a simple URI with a port."""
uri = self.test_class.from_string(basic_uri_with_port)
assert uri.scheme == 'ftp'
assert uri.authority == basic_uri_with_port[6:]
assert uri.host != uri.authority
assert str(uri.port) == '21'
assert uri.path is None
assert uri.query is None
assert uri.fragment is None
assert uri.userinfo is None
def test_handles_uri_with_port_and_userinfo(
self, uri_with_port_and_userinfo):
"""
Test that self.test_class can handle a URI with a port and userinfo.
"""
uri = self.test_class.from_string(uri_with_port_and_userinfo)
assert uri.scheme == 'ssh'
# 6 == len('ftp://')
assert uri.authority == uri_with_port_and_userinfo[6:]
assert uri.host != uri.authority
assert str(uri.port) == '22'
assert uri.path is None
assert uri.query is None
assert uri.fragment is None
assert uri.userinfo == 'user:pass'
def test_handles_basic_uri_with_path(self, basic_uri_with_path):
"""Test that self.test_class can handle a URI with a path."""
uri = self.test_class.from_string(basic_uri_with_path)
assert uri.scheme == 'http'
assert basic_uri_with_path == (uri.scheme + '://' + uri.authority
+ uri.path)
assert uri.host == uri.authority
assert uri.path == '/path/to/resource'
assert uri.query is None
assert uri.fragment is None
assert uri.userinfo is None
assert uri.port is None
def test_handles_uri_with_path_and_query(self, uri_with_path_and_query):
"""
Test that self.test_class can handle a URI with a path and query.
"""
uri = self.test_class.from_string(uri_with_path_and_query)
assert uri.scheme == 'http'
assert uri.host == uri.authority
assert uri.path == '/path/to/resource'
assert uri.query == 'key=value'
assert uri.fragment is None
assert uri.userinfo is None
assert uri.port is None
def test_handles_uri_with_everything(self, uri_with_everything):
"""
Test that self.test_class can handle and with everything in it.
"""
uri = self.test_class.from_string(uri_with_everything)
assert uri.scheme == 'https'
assert uri.path == '/path/to/resource'
assert uri.query == 'key=value'
assert uri.fragment == 'fragment'
assert uri.userinfo == 'user:pass'
assert str(uri.port) == '443'
def test_handles_relative_uri(self, relative_uri):
"""Test that self.test_class can handle a relative URI."""
uri = self.test_class.from_string(relative_uri)
assert uri.scheme is None
assert uri.authority == relative_uri[2:]
class BaseTestUnsplits:
test_class = None
def test_basic_uri_unsplits(self, basic_uri):
uri = self.test_class.from_string(basic_uri)
assert uri.unsplit() == basic_uri
def test_basic_uri_with_port_unsplits(self, basic_uri_with_port):
uri = self.test_class.from_string(basic_uri_with_port)
assert uri.unsplit() == basic_uri_with_port
def test_uri_with_port_and_userinfo_unsplits(self,
uri_with_port_and_userinfo):
uri = self.test_class.from_string(uri_with_port_and_userinfo)
assert uri.unsplit() == uri_with_port_and_userinfo
def test_basic_uri_with_path_unsplits(self, basic_uri_with_path):
uri = self.test_class.from_string(basic_uri_with_path)
assert uri.unsplit() == basic_uri_with_path
def test_uri_with_path_and_query_unsplits(self, uri_with_path_and_query):
uri = self.test_class.from_string(uri_with_path_and_query)
assert uri.unsplit() == uri_with_path_and_query
def test_uri_with_everything_unsplits(self, uri_with_everything):
uri = self.test_class.from_string(uri_with_everything)
assert uri.unsplit() == uri_with_everything
def test_relative_uri_unsplits(self, relative_uri):
uri = self.test_class.from_string(relative_uri)
assert uri.unsplit() == relative_uri
def test_absolute_path_uri_unsplits(self, absolute_path_uri):
uri = self.test_class.from_string(absolute_path_uri)
assert uri.unsplit() == absolute_path_uri

View File

@@ -1,4 +1,70 @@
# -*- coding: utf-8 -*-
import sys
import pytest
SNOWMAN = b'\xe2\x98\x83'
valid_hosts = [
'[21DA:00D3:0000:2F3B:02AA:00FF:FE28:9C5A]', '[::1]',
'[21DA:D3:0:2F3B:2AA:FF:FE28:9C5A]', '[FE80::2AA:FF:FE9A:4CA2]',
'[FF02::2]', '[FF02:3::5]', '[FF02:0:0:0:0:0:0:2]',
'[FF02:30:0:0:0:0:0:5]', '127.0.0.1', 'www.example.com', 'localhost',
'http-bin.org',
]
invalid_hosts = [
'[FF02::3::5]', # IPv6 can only have one ::
'[FADF:01]', # Not properly compacted (missing a :)
'localhost:80:80:80', # Too many ports
'256.256.256.256', # Invalid IPv4 Address
SNOWMAN.decode('utf-8')
]
@pytest.fixture(params=valid_hosts)
def basic_uri(request):
return 'http://%s' % request.param
@pytest.fixture(params=valid_hosts)
def basic_uri_with_port(request):
return 'ftp://%s:21' % request.param
@pytest.fixture(params=valid_hosts)
def uri_with_port_and_userinfo(request):
return 'ssh://user:pass@%s:22' % request.param
@pytest.fixture(params=valid_hosts)
def basic_uri_with_path(request):
return 'http://%s/path/to/resource' % request.param
@pytest.fixture(params=valid_hosts)
def uri_with_path_and_query(request):
return 'http://%s/path/to/resource?key=value' % request.param
@pytest.fixture(params=valid_hosts)
def uri_with_everything(request):
return 'https://user:pass@%s:443/path/to/resource?key=value#fragment' % (
request.param)
@pytest.fixture(params=valid_hosts)
def relative_uri(request):
return '//%s' % request.param
@pytest.fixture
def absolute_path_uri():
return '/path/to/file'
@pytest.fixture(params=invalid_hosts)
def invalid_uri(request):
return 'https://%s' % request.param
sys.path.insert(0, '.')

46
tests/test_parseresult.py Normal file
View File

@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015 Ian 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.
from rfc3986 import parseresult as pr
from . import base
class TestParseResultParsesURIs(base.BaseTestParsesURIs):
test_class = pr.ParseResult
class TestParseResultUnsplits(base.BaseTestUnsplits):
test_class = pr.ParseResult
class TestStdlibShims:
def test_uri_with_everything(self, uri_with_everything):
uri = pr.ParseResult.from_string(uri_with_everything)
assert uri.host == uri.hostname
assert uri.netloc == uri.authority
assert uri.query == uri.params
assert uri.geturl() == uri.unsplit()
def test_creates_a_copy_with_a_new_path(uri_with_everything):
uri = pr.ParseResult.from_string(uri_with_everything)
new_uri = uri.copy_with(path='/parse/result/tests/are/fun')
assert new_uri.path == '/parse/result/tests/are/fun'
def test_creates_a_copy_with_a_new_port(basic_uri):
uri = pr.ParseResult.from_string(basic_uri)
new_uri = uri.copy_with(port=443)
assert new_uri.port == 443

View File

@@ -45,6 +45,20 @@ def test_urlparse_a_unicode_hostname():
assert parsed.host == unicode_url[7:]
def test_urlparse_a_unicode_hostname_with_auth():
url = b'http://userinfo@' + SNOWMAN + b'.com'
parsed = urlparse(url)
assert parsed.userinfo == 'userinfo'
def test_urlparse_an_invalid_authority_parses_port():
url = 'http://foo:b@r@[::1]:80/get'
parsed = urlparse(url)
assert parsed.port == 80
assert parsed.userinfo == 'foo:b@r'
assert parsed.hostname == '[::1]'
def test_unsplit_idna_a_unicode_hostname():
parsed = urlparse(SNOWMAN_HOST)
assert parsed.unsplit(use_idna=True) == SNOWMAN_IDNA_HOST

View File

@@ -5,67 +5,7 @@ from rfc3986.exceptions import InvalidAuthority, ResolutionError
from rfc3986.misc import URI_MATCHER
from rfc3986.uri import URIReference
valid_hosts = [
'[21DA:00D3:0000:2F3B:02AA:00FF:FE28:9C5A]', '[::1]',
'[21DA:D3:0:2F3B:2AA:FF:FE28:9C5A]', '[FE80::2AA:FF:FE9A:4CA2]',
'[FF02::2]', '[FF02:3::5]', '[FF02:0:0:0:0:0:0:2]',
'[FF02:30:0:0:0:0:0:5]', '127.0.0.1', 'www.example.com', 'localhost',
'http-bin.org',
]
invalid_hosts = [
'[FF02::3::5]', # IPv6 can only have one ::
'[FADF:01]', # Not properly compacted (missing a :)
'localhost:80:80:80', # Too many ports
'256.256.256.256' # Invalid IPv4 Address
]
@pytest.fixture(params=valid_hosts)
def basic_uri(request):
return 'http://%s' % request.param
@pytest.fixture(params=valid_hosts)
def basic_uri_with_port(request):
return 'ftp://%s:21' % request.param
@pytest.fixture(params=valid_hosts)
def uri_with_port_and_userinfo(request):
return 'ssh://user:pass@%s:22' % request.param
@pytest.fixture(params=valid_hosts)
def basic_uri_with_path(request):
return 'http://%s/path/to/resource' % request.param
@pytest.fixture(params=valid_hosts)
def uri_with_path_and_query(request):
return 'http://%s/path/to/resource?key=value' % request.param
@pytest.fixture(params=valid_hosts)
def uri_with_everything(request):
return 'https://user:pass@%s:443/path/to/resource?key=value#fragment' % (
request.param)
@pytest.fixture(params=valid_hosts)
def relative_uri(request):
return '//%s' % request.param
@pytest.fixture
def absolute_path_uri():
return '/path/to/file'
@pytest.fixture(params=invalid_hosts)
def invalid_uri(request):
return 'https://%s' % request.param
from . import base
@pytest.fixture
@@ -73,85 +13,9 @@ def scheme_and_path_uri():
return 'mailto:user@example.com'
class TestURIReferenceParsesURIs:
class TestURIReferenceParsesURIs(base.BaseTestParsesURIs):
"""Tests for URIReference handling of URIs."""
def test_handles_basic_uri(self, basic_uri):
"""Test that URIReference can handle a simple URI."""
uri = URIReference.from_string(basic_uri)
assert uri.scheme == 'http'
assert uri.authority == basic_uri[7:] # len('http://')
assert uri.host == uri.authority
assert uri.path is None
assert uri.query is None
assert uri.fragment is None
assert uri.port is None
assert uri.userinfo is None
def test_handles_basic_uri_with_port(self, basic_uri_with_port):
"""Test that URIReference can handle a simple URI with a port."""
uri = URIReference.from_string(basic_uri_with_port)
assert uri.scheme == 'ftp'
assert uri.authority == basic_uri_with_port[6:] # len('ftp://')
assert uri.host != uri.authority
assert uri.port == '21'
assert uri.path is None
assert uri.query is None
assert uri.fragment is None
assert uri.userinfo is None
def test_handles_uri_with_port_and_userinfo(
self, uri_with_port_and_userinfo):
"""
Test that URIReference can handle a URI with a port and userinfo.
"""
uri = URIReference.from_string(uri_with_port_and_userinfo)
assert uri.scheme == 'ssh'
# 6 == len('ftp://')
assert uri.authority == uri_with_port_and_userinfo[6:]
assert uri.host != uri.authority
assert uri.port == '22'
assert uri.path is None
assert uri.query is None
assert uri.fragment is None
assert uri.userinfo == 'user:pass'
def test_handles_basic_uri_with_path(self, basic_uri_with_path):
"""Test that URIReference can handle a URI with a path."""
uri = URIReference.from_string(basic_uri_with_path)
assert uri.scheme == 'http'
assert basic_uri_with_path == (uri.scheme + '://' + uri.authority
+ uri.path)
assert uri.host == uri.authority
assert uri.path == '/path/to/resource'
assert uri.query is None
assert uri.fragment is None
assert uri.userinfo is None
assert uri.port is None
def test_handles_uri_with_path_and_query(self, uri_with_path_and_query):
"""
Test that URIReference can handle a URI with a path and query.
"""
uri = URIReference.from_string(uri_with_path_and_query)
assert uri.scheme == 'http'
assert uri.host == uri.authority
assert uri.path == '/path/to/resource'
assert uri.query == 'key=value'
assert uri.fragment is None
assert uri.userinfo is None
assert uri.port is None
def test_handles_uri_with_everything(self, uri_with_everything):
"""
Test that URIReference can handle and with everything in it.
"""
uri = URIReference.from_string(uri_with_everything)
assert uri.scheme == 'https'
assert uri.path == '/path/to/resource'
assert uri.query == 'key=value'
assert uri.fragment == 'fragment'
assert uri.userinfo == 'user:pass'
assert uri.port == '443'
test_class = URIReference
def test_authority_info_raises_InvalidAuthority(self, invalid_uri):
"""Test that an invalid IPv6 is caught by authority_info()."""
@@ -166,12 +30,6 @@ class TestURIReferenceParsesURIs:
assert uri.userinfo is None
assert uri.port is None
def test_handles_relative_uri(self, relative_uri):
"""Test that URIReference can handle a relative URI."""
uri = URIReference.from_string(relative_uri)
assert uri.scheme is None
assert uri.authority == relative_uri[2:]
def test_handles_absolute_path_uri(self, absolute_path_uri):
"""Test that URIReference can handle a path-only URI."""
uri = URIReference.from_string(absolute_path_uri)
@@ -182,9 +40,13 @@ class TestURIReferenceParsesURIs:
'port': None,
}
def test_scheme_and_path_uri_is_valid(self, scheme_and_path_uri):
uri = self.test_class.from_string(scheme_and_path_uri)
assert uri.is_valid() is True
def test_handles_scheme_and_path_uri(self, scheme_and_path_uri):
"""Test that URIReference can handle a `scheme:path` URI."""
uri = URIReference.from_string(scheme_and_path_uri)
"""Test that self.test_class can handle a `scheme:path` URI."""
uri = self.test_class.from_string(scheme_and_path_uri)
assert uri.path == 'user@example.com'
assert uri.scheme == 'mailto'
assert uri.query is None
@@ -276,42 +138,11 @@ class TestURIValidation:
assert uri.is_valid() is False
class TestURIReferenceUnsplits:
def test_basic_uri_unsplits(self, basic_uri):
uri = URIReference.from_string(basic_uri)
assert uri.unsplit() == basic_uri
def test_basic_uri_with_port_unsplits(self, basic_uri_with_port):
uri = URIReference.from_string(basic_uri_with_port)
assert uri.unsplit() == basic_uri_with_port
def test_uri_with_port_and_userinfo_unsplits(self,
uri_with_port_and_userinfo):
uri = URIReference.from_string(uri_with_port_and_userinfo)
assert uri.unsplit() == uri_with_port_and_userinfo
def test_basic_uri_with_path_unsplits(self, basic_uri_with_path):
uri = URIReference.from_string(basic_uri_with_path)
assert uri.unsplit() == basic_uri_with_path
def test_uri_with_path_and_query_unsplits(self, uri_with_path_and_query):
uri = URIReference.from_string(uri_with_path_and_query)
assert uri.unsplit() == uri_with_path_and_query
def test_uri_with_everything_unsplits(self, uri_with_everything):
uri = URIReference.from_string(uri_with_everything)
assert uri.unsplit() == uri_with_everything
def test_relative_uri_unsplits(self, relative_uri):
uri = URIReference.from_string(relative_uri)
assert uri.unsplit() == relative_uri
def test_absolute_path_uri_unsplits(self, absolute_path_uri):
uri = URIReference.from_string(absolute_path_uri)
assert uri.unsplit() == absolute_path_uri
class TestURIReferenceUnsplits(base.BaseTestUnsplits):
test_class = URIReference
def test_scheme_and_path_uri_unsplits(self, scheme_and_path_uri):
uri = URIReference.from_string(scheme_and_path_uri)
uri = self.test_class.from_string(scheme_and_path_uri)
assert uri.unsplit() == scheme_and_path_uri

View File

@@ -5,6 +5,12 @@ envlist = py26,py27,py32,py33,py34,pypy,{py27,py34}-flake8
pip_pre = False
deps =
-rdev-requirements.txt
commands =
py.test {posargs:--cov rfc3986 tests/}
coverage report --fail-under 100 -m
[testenv:pypy]
deps = {[testenv]deps}
commands = py.test {posargs}
[testenv:py27-flake8]