19
19
from cStringIO import StringIO
21
from bzrlib import errors
22
from bzrlib.transport.http import response
21
23
from bzrlib.tests import TestCase
22
from bzrlib.transport.http.response import RangeFile, ResponseRange
23
from bzrlib.errors import InvalidRange
26
26
class TestResponseRange(TestCase):
27
27
"""Test the ResponseRange class."""
29
29
def test_cmp(self):
30
r1 = ResponseRange(0, 10, 0)
31
r2 = ResponseRange(15, 20, 10)
30
RR = response.ResponseRange
32
33
self.assertTrue(r1 < r2)
33
34
self.assertFalse(r1 > r2)
34
35
self.assertTrue(r1 < 5)
35
36
self.assertFalse(r2 < 5)
37
self.assertEqual(ResponseRange(0, 10, 5), ResponseRange(0, 10, 5))
38
self.assertNotEqual(ResponseRange(0, 10, 5), ResponseRange(0, 8, 5))
39
self.assertNotEqual(ResponseRange(0, 10, 5), ResponseRange(0, 10, 6))
38
self.assertEqual(RR(0, 10, 5), RR(0, 10, 5))
39
self.assertNotEqual(RR(0, 10, 5), RR(0, 8, 5))
40
self.assertNotEqual(RR(0, 10, 5), RR(0, 10, 6))
41
42
def test_sort_list(self):
42
lst = [ResponseRange(3, 8, 0), 5, ResponseRange(3, 7, 0), 6]
43
"""Ensure longer ranges are sorted after shorter ones"""
44
RR = response.ResponseRange
45
lst = [RR(3, 8, 0), 5, RR(3, 7, 0), 6]
44
self.assertEqual([ResponseRange(3,7,0), ResponseRange(3,8,0), 5, 6],
47
self.assertEqual([RR(3,7,0), RR(3,8,0), 5, 6], lst)
48
50
class TestRangeFile(TestCase):
52
54
content = "abcdefghijklmnopqrstuvwxyz"
53
self.fp = RangeFile('foo', StringIO(content))
55
self.fp = response.RangeFile('foo', StringIO(content))
54
56
self.fp._add_range(0, 9, 0)
55
57
self.fp._add_range(20, 29, 10)
56
58
self.fp._add_range(30, 39, 15)
74
76
def test_invalid_accesses(self):
75
77
"""Test so that invalid accesses trigger errors."""
77
self.assertRaises(InvalidRange, self.fp.read, 2)
79
self.assertRaises(errors.InvalidRange, self.fp.read, 2)
79
self.assertRaises(InvalidRange, self.fp.read, 2)
81
self.assertRaises(errors.InvalidRange, self.fp.read, 2)
81
self.assertRaises(InvalidRange, self.fp.read, 2)
83
self.assertRaises(errors.InvalidRange, self.fp.read, 2)
83
85
def test__finish_ranges(self):
84
86
"""Test that after RangeFile._finish_ranges the list is sorted."""
118
120
self.assertRaises(ValueError, self.fp.seek, 0, 4)
119
121
self.assertRaises(ValueError, self.fp.seek, 0, -1)
124
class TestHttpRangeResponse(TestCase):
126
def assertMatches(self, regex, text, groups):
127
"""Check that the regex matches and returns the right values"""
128
m = regex.match(text)
129
self.assertNotEqual(None, m, "text %s did not match regex" % (text,))
131
self.assertEqual(groups, m.groups())
133
def test_range_re(self):
134
"""Test that we match valid ranges."""
135
regex = response.HttpRangeResponse.CONTENT_RANGE_RE
136
self.assertMatches(regex, 'bytes 1-10/11', ('bytes', '1', '10', '11'))
137
self.assertMatches(regex,
138
'\tbytes 1-10/11 ', ('bytes', '1', '10', '11'))
139
self.assertMatches(regex,
140
'\tbytes 2123-4242/1231 ', ('bytes', '2123', '4242', '1231'))
141
self.assertMatches(regex,
142
' chars 1-2/3', ('chars', '1', '2', '3'))
144
def test__parse_range(self):
145
"""Test that _parse_range acts reasonably."""
146
content = StringIO('')
147
# Ignore this for now, we only need a class because
148
# _parse_range is not static, and it isn't static
149
# because it tries to be nice and tell you what path
151
f = response.HttpRangeResponse('', 'bytes 1-3/2', content)
153
self.assertEqual((1,2), f._parse_range('bytes 1-2/3'))
154
self.assertEqual((10,20), f._parse_range('bytes 10-20/2'))
156
self.assertRaises(errors.InvalidHttpRange, f._parse_range, 'char 1-3/2')
157
self.assertRaises(errors.InvalidHttpRange, f._parse_range, 'bytes a-3/2')
159
def test_smoketest(self):
160
"""A basic test that HttpRangeResponse is reasonable."""
161
content = StringIO('0123456789')
162
f = response.HttpRangeResponse('http://foo', 'bytes 1-10/9', content)
163
self.assertEqual([response.ResponseRange(1,10,0)], f._ranges)
166
self.assertRaises(errors.InvalidRange, f.read, 2)
168
self.assertEqual('012345', f.read(6))