[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.17-1283-gcf603cf
ukai at chromium.org
ukai at chromium.org
Tue Jan 5 23:53:10 UTC 2010
The following commit has been merged in the webkit-1.1 branch:
commit f952d86a688f2d8b612f4cb09a78c0b1ce997d3d
Author: ukai at chromium.org <ukai at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Fri Dec 18 02:38:01 2009 +0000
2009-12-17 Yuzo Fujishima <yuzo at google.com>
Reviewed by Alexey Proskuryakov.
Update pywebsocket to 0.4.5 and make handshake checking stricter
https://bugs.webkit.org/show_bug.cgi?id=32249
* Scripts/run-webkit-tests:
* pywebsocket/mod_pywebsocket/handshake.py:
* pywebsocket/mod_pywebsocket/memorizingfile.py: Added.
* pywebsocket/mod_pywebsocket/standalone.py:
* pywebsocket/setup.py:
* pywebsocket/test/test_handshake.py:
* pywebsocket/test/test_memorizingfile.py: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@52296 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index 6f5f2fa..9a15ebe 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,3 +1,18 @@
+2009-12-17 Yuzo Fujishima <yuzo at google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Update pywebsocket to 0.4.5 and make handshake checking stricter
+ https://bugs.webkit.org/show_bug.cgi?id=32249
+
+ * Scripts/run-webkit-tests:
+ * pywebsocket/mod_pywebsocket/handshake.py:
+ * pywebsocket/mod_pywebsocket/memorizingfile.py: Added.
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_handshake.py:
+ * pywebsocket/test/test_memorizingfile.py: Added.
+
2009-12-17 Eric Seidel <eric at webkit.org>
Reviewed by Adam Barth.
diff --git a/WebKitTools/Scripts/run-webkit-tests b/WebKitTools/Scripts/run-webkit-tests
index 6dd8339..8709946 100755
--- a/WebKitTools/Scripts/run-webkit-tests
+++ b/WebKitTools/Scripts/run-webkit-tests
@@ -1455,6 +1455,7 @@ sub openWebSocketServerIfNeeded()
"-d", "$webSocketHandlerDir",
"-s", "$webSocketHandlerScanDir",
"-l", "$logFile",
+ "--strict",
);
# wss is disabled until all platforms support pyOpenSSL.
# my @argsSecure = (
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/handshake.py b/WebKitTools/pywebsocket/mod_pywebsocket/handshake.py
index a67aadd..14d5afc 100644
--- a/WebKitTools/pywebsocket/mod_pywebsocket/handshake.py
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/handshake.py
@@ -39,14 +39,14 @@ not suitable because they don't allow direct raw bytes writing/reading.
import re
+import util
+
_DEFAULT_WEB_SOCKET_PORT = 80
_DEFAULT_WEB_SOCKET_SECURE_PORT = 443
_WEB_SOCKET_SCHEME = 'ws'
_WEB_SOCKET_SECURE_SCHEME = 'wss'
-_METHOD_LINE = re.compile(r'^GET ([^ ]+) HTTP/1.1\r\n$')
-
_MANDATORY_HEADERS = [
# key, expected value or None
['Upgrade', 'WebSocket'],
@@ -55,6 +55,24 @@ _MANDATORY_HEADERS = [
['Origin', None],
]
+_FIRST_FIVE_LINES = map(re.compile, [
+ r'^GET /[\S]+ HTTP/1.1\r\n$',
+ r'^Upgrade: WebSocket\r\n$',
+ r'^Connection: Upgrade\r\n$',
+ r'^Host: [\S]+\r\n$',
+ r'^Origin: [\S]+\r\n$',
+])
+
+# FIXME: Cookie headers also being in restricted WebSocket syntax.
+_SIXTH_AND_LATER = re.compile(
+ r'^'
+ r'(WebSocket-Protocol: [\x20-\x7e]+\r\n)?'
+ r'([Cc][Oo][Oo][Kk][Ii][Ee]:[^\r]*\r\n)*'
+ r'([Cc][Oo][Oo][Kk][Ii][Ee]2:[^\r]*\r\n)?'
+ r'([Cc][Oo][Oo][Kk][Ii][Ee]:[^\r]*\r\n)*'
+ r'\r\n')
+
+
def _default_port(is_secure):
if is_secure:
@@ -75,19 +93,22 @@ def _validate_protocol(protocol):
if not protocol:
raise HandshakeError('Invalid WebSocket-Protocol: empty')
for c in protocol:
- if not 0x21 <= ord(c) <= 0x7e:
+ if not 0x20 <= ord(c) <= 0x7e:
raise HandshakeError('Illegal character in protocol: %r' % c)
class Handshaker(object):
"""This class performs Web Socket handshake."""
- def __init__(self, request, dispatcher):
+ def __init__(self, request, dispatcher, strict=False):
"""Construct an instance.
Args:
request: mod_python request.
dispatcher: Dispatcher (dispatch.Dispatcher).
+ strict: Strictly check handshake request. Default: False.
+ If True, request.connection must provide get_memorized_lines
+ method.
Handshaker will add attributes such as ws_resource in performing
handshake.
@@ -95,6 +116,7 @@ class Handshaker(object):
self._request = request
self._dispatcher = dispatcher
+ self._strict = strict
def do_handshake(self):
"""Perform Web Socket Handshake."""
@@ -173,6 +195,28 @@ class Handshaker(object):
if actual_value != expected_value:
raise HandshakeError('Illegal value for header %s: %s' %
(key, actual_value))
+ if self._strict:
+ try:
+ lines = self._request.connection.get_memorized_lines()
+ except AttributeError, e:
+ util.prepend_message_to_exception(
+ 'Strict handshake is specified but the connection '
+ 'doesn\'t provide get_memorized_lines()', e)
+ raise
+ self._check_first_lines(lines)
+
+ def _check_first_lines(self, lines):
+ if len(lines) < len(_FIRST_FIVE_LINES):
+ raise HandshakeError('Too few header lines: %d' % len(lines))
+ for line, regexp in zip(lines, _FIRST_FIVE_LINES):
+ if not regexp.search(line):
+ raise HandshakeError('Unexpected header: %r doesn\'t match %r'
+ % (line, regexp.pattern))
+ sixth_and_later = ''.join(lines[5:])
+ if not _SIXTH_AND_LATER.search(sixth_and_later):
+ raise HandshakeError('Unexpected header: %r doesn\'t match %r'
+ % (sixth_and_later,
+ _SIXTH_AND_LATER.pattern))
# vi:sts=4 sw=4 et
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/memorizingfile.py b/WebKitTools/pywebsocket/mod_pywebsocket/memorizingfile.py
new file mode 100644
index 0000000..2f8a54e
--- /dev/null
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/memorizingfile.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""Memorizing file.
+
+A memorizing file wraps a file and memorizes lines read by readline.
+"""
+
+
+import sys
+
+
+class MemorizingFile(object):
+ """MemorizingFile wraps a file and memorizes lines read by readline.
+
+ Note that data read by other methods are not memorized. This behavior
+ is good enough for memorizing lines SimpleHTTPServer reads before
+ the control reaches WebSocketRequestHandler.
+ """
+ def __init__(self, file_, max_memorized_lines=sys.maxint):
+ """Construct an instance.
+
+ Args:
+ file_: the file object to wrap.
+ max_memorized_lines: the maximum number of lines to memorize.
+ Only the first max_memorized_lines are memorized.
+ Default: sys.maxint.
+ """
+ self._file = file_
+ self._memorized_lines = []
+ self._max_memorized_lines = max_memorized_lines
+
+ def __getattribute__(self, name):
+ if name in ('_file', '_memorized_lines', '_max_memorized_lines',
+ 'readline', 'get_memorized_lines'):
+ return object.__getattribute__(self, name)
+ return self._file.__getattribute__(name)
+
+ def readline(self):
+ """Override file.readline and memorize the line read."""
+
+ line = self._file.readline()
+ if line and len(self._memorized_lines) < self._max_memorized_lines:
+ self._memorized_lines.append(line)
+ return line
+
+ def get_memorized_lines(self):
+ """Get lines memorized so far."""
+ return self._memorized_lines
+
+
+# vi:sts=4 sw=4 et
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py b/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
index 6217585..0a1736e 100644
--- a/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
@@ -75,6 +75,7 @@ except ImportError:
import dispatch
import handshake
+import memorizingfile
import util
@@ -88,6 +89,8 @@ _LOG_LEVELS = {
_DEFAULT_LOG_MAX_BYTES = 1024 * 256
_DEFAULT_LOG_BACKUP_COUNT = 5
+# 1024 is practically large enough to contain WebSocket handshake lines.
+_MAX_MEMORIZED_LINES = 1024
def _print_warnings_if_any(dispatcher):
warnings = dispatcher.source_warnings()
@@ -129,6 +132,10 @@ class _StandaloneConnection(object):
"""Mimic mp_conn.read()."""
return self._request_handler.rfile.read(length)
+ def get_memorized_lines(self):
+ """Get memorized lines."""
+ return self._request_handler.rfile.get_memorized_lines()
+
class _StandaloneRequest(object):
"""Mimic mod_python request."""
@@ -198,7 +205,9 @@ class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""Override SocketServer.StreamRequestHandler.setup."""
self.connection = self.request
- self.rfile = socket._fileobject(self.request, 'rb', self.rbufsize)
+ self.rfile = memorizingfile.MemorizingFile(
+ socket._fileobject(self.request, 'rb', self.rbufsize),
+ max_memorized_lines=_MAX_MEMORIZED_LINES)
self.wfile = socket._fileobject(self.request, 'wb', self.wbufsize)
def __init__(self, *args, **keywords):
@@ -206,8 +215,9 @@ class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
self, WebSocketRequestHandler.options.use_tls)
self._dispatcher = WebSocketRequestHandler.options.dispatcher
self._print_warnings_if_any()
- self._handshaker = handshake.Handshaker(self._request,
- self._dispatcher)
+ self._handshaker = handshake.Handshaker(
+ self._request, self._dispatcher,
+ WebSocketRequestHandler.options.strict)
SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(
self, *args, **keywords)
@@ -302,6 +312,8 @@ def _main():
parser.add_option('--log_count', dest='log_count', type='int',
default=_DEFAULT_LOG_BACKUP_COUNT,
help='Log backup count')
+ parser.add_option('--strict', dest='strict', action='store_true',
+ default=False, help='Strictly check handshake request')
options = parser.parse_args()[0]
os.chdir(options.document_root)
diff --git a/WebKitTools/pywebsocket/setup.py b/WebKitTools/pywebsocket/setup.py
index df05fef..d552d91 100644
--- a/WebKitTools/pywebsocket/setup.py
+++ b/WebKitTools/pywebsocket/setup.py
@@ -56,7 +56,7 @@ setup(author='Yuzo Fujishima',
name=_PACKAGE_NAME,
packages=[_PACKAGE_NAME],
url='http://code.google.com/p/pywebsocket/',
- version='0.4.3',
+ version='0.4.5',
)
diff --git a/WebKitTools/pywebsocket/test/test_handshake.py b/WebKitTools/pywebsocket/test/test_handshake.py
index dd1f65c..c4c4590 100644
--- a/WebKitTools/pywebsocket/test/test_handshake.py
+++ b/WebKitTools/pywebsocket/test/test_handshake.py
@@ -214,11 +214,142 @@ _BAD_REQUESTS = (
'Connection':'Upgrade',
'Host':'example.com',
'Origin':'http://example.com',
- 'WebSocket-Protocol':'illegal protocol',
+ 'WebSocket-Protocol':'illegal\x09protocol',
}
),
)
+_STRICTLY_GOOD_REQUESTS = (
+ (
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ '\r\n',
+ ),
+ ( # WebSocket-Protocol
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ 'WebSocket-Protocol: sample\r\n',
+ '\r\n',
+ ),
+ ( # WebSocket-Protocol and Cookie
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ 'WebSocket-Protocol: sample\r\n',
+ 'Cookie: xyz\r\n'
+ '\r\n',
+ ),
+ ( # Cookie
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ 'Cookie: abc/xyz\r\n'
+ 'Cookie2: $Version=1\r\n'
+ 'Cookie: abc\r\n'
+ '\r\n',
+ ),
+)
+
+_NOT_STRICTLY_GOOD_REQUESTS = (
+ ( # Extra space after GET
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ '\r\n',
+ ),
+ ( # Resource name doesn't stat with '/'
+ 'GET demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ '\r\n',
+ ),
+ ( # No space after :
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade:WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ '\r\n',
+ ),
+ ( # Lower case Upgrade header
+ 'GET /demo HTTP/1.1\r\n',
+ 'upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ '\r\n',
+ ),
+ ( # Connection comes before Upgrade
+ 'GET /demo HTTP/1.1\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ '\r\n',
+ ),
+ ( # Origin comes before Host
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Origin: http://example.com\r\n',
+ 'Host: example.com\r\n',
+ '\r\n',
+ ),
+ ( # Host continued to the next line
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example\r\n',
+ ' .com\r\n',
+ 'Origin: http://example.com\r\n',
+ '\r\n',
+ ),
+ ( # Cookie comes before WebSocket-Protocol
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ 'Cookie: xyz\r\n'
+ 'WebSocket-Protocol: sample\r\n',
+ '\r\n',
+ ),
+ ( # Unknown header
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ 'Content-Type: text/html\r\n'
+ '\r\n',
+ ),
+ ( # Cookie with continuation lines
+ 'GET /demo HTTP/1.1\r\n',
+ 'Upgrade: WebSocket\r\n',
+ 'Connection: Upgrade\r\n',
+ 'Host: example.com\r\n',
+ 'Origin: http://example.com\r\n',
+ 'Cookie: xyz\r\n',
+ ' abc\r\n',
+ ' defg\r\n',
+ '\r\n',
+ ),
+)
+
def _create_request(request_def):
conn = mock.MockConn('')
@@ -229,13 +360,37 @@ def _create_request(request_def):
connection=conn)
+def _create_get_memorized_lines(lines):
+ def get_memorized_lines():
+ return lines
+ return get_memorized_lines
+
+
+def _create_requests_with_lines(request_lines_set):
+ requests = []
+ for lines in request_lines_set:
+ request = _create_request(_GOOD_REQUEST)
+ request.connection.get_memorized_lines = _create_get_memorized_lines(
+ lines)
+ requests.append(request)
+ return requests
+
+
class HandshakerTest(unittest.TestCase):
def test_validate_protocol(self):
handshake._validate_protocol('sample') # should succeed.
handshake._validate_protocol('Sample') # should succeed.
+ handshake._validate_protocol('sample\x20protocol') # should succeed.
+ handshake._validate_protocol('sample\x7eprotocol') # should succeed.
+ self.assertRaises(handshake.HandshakeError,
+ handshake._validate_protocol,
+ '')
self.assertRaises(handshake.HandshakeError,
handshake._validate_protocol,
- 'sample protocol')
+ 'sample\x19protocol')
+ self.assertRaises(handshake.HandshakeError,
+ handshake._validate_protocol,
+ 'sample\x7fprotocol')
self.assertRaises(handshake.HandshakeError,
handshake._validate_protocol,
# "Japan" in Japanese
@@ -308,6 +463,22 @@ class HandshakerTest(unittest.TestCase):
mock.MockDispatcher())
self.assertRaises(handshake.HandshakeError, handshaker.do_handshake)
+ def test_strictly_good_requests(self):
+ for request in _create_requests_with_lines(_STRICTLY_GOOD_REQUESTS):
+ strict_handshaker = handshake.Handshaker(request,
+ mock.MockDispatcher(),
+ True)
+ strict_handshaker.do_handshake()
+
+ def test_not_strictly_good_requests(self):
+ for request in _create_requests_with_lines(_NOT_STRICTLY_GOOD_REQUESTS):
+ strict_handshaker = handshake.Handshaker(request,
+ mock.MockDispatcher(),
+ True)
+ self.assertRaises(handshake.HandshakeError,
+ strict_handshaker.do_handshake)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/WebKitTools/pywebsocket/test/test_memorizingfile.py b/WebKitTools/pywebsocket/test/test_memorizingfile.py
new file mode 100644
index 0000000..2de77ba
--- /dev/null
+++ b/WebKitTools/pywebsocket/test/test_memorizingfile.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""Tests for memorizingfile module."""
+
+
+import StringIO
+import unittest
+
+import config # This must be imported before mod_pywebsocket.
+from mod_pywebsocket import memorizingfile
+
+
+class UtilTest(unittest.TestCase):
+ def check(self, memorizing_file, num_read, expected_list):
+ for unused in range(num_read):
+ memorizing_file.readline()
+ actual_list = memorizing_file.get_memorized_lines()
+ self.assertEqual(len(expected_list), len(actual_list))
+ for expected, actual in zip(expected_list, actual_list):
+ self.assertEqual(expected, actual)
+
+ def test_get_memorized_lines(self):
+ memorizing_file = memorizingfile.MemorizingFile(StringIO.StringIO(
+ 'Hello\nWorld\nWelcome'))
+ self.check(memorizing_file, 3, ['Hello\n', 'World\n', 'Welcome'])
+
+ def test_get_memorized_lines_limit_memorized_lines(self):
+ memorizing_file = memorizingfile.MemorizingFile(StringIO.StringIO(
+ 'Hello\nWorld\nWelcome'), 2)
+ self.check(memorizing_file, 3, ['Hello\n', 'World\n'])
+
+ def test_get_memorized_lines_empty_file(self):
+ memorizing_file = memorizingfile.MemorizingFile(StringIO.StringIO(
+ ''))
+ self.check(memorizing_file, 10, [])
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
+# vi:sts=4 sw=4 et
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list