[Checkins] SVN: zope.testbrowser/tags/3.5.1/ - Tag 3.5.1
Sidnei da Silva
sidnei at enfoldsystems.com
Fri Oct 10 12:57:17 EDT 2008
Log message for revision 92000:
- Tag 3.5.1
Changed:
A zope.testbrowser/tags/3.5.1/
D zope.testbrowser/tags/3.5.1/CHANGES.txt
A zope.testbrowser/tags/3.5.1/CHANGES.txt
U zope.testbrowser/tags/3.5.1/bootstrap.py
D zope.testbrowser/tags/3.5.1/buildout.cfg
A zope.testbrowser/tags/3.5.1/buildout.cfg
D zope.testbrowser/tags/3.5.1/setup.py
A zope.testbrowser/tags/3.5.1/setup.py
D zope.testbrowser/tags/3.5.1/src/zope/testbrowser/testing.py
A zope.testbrowser/tags/3.5.1/src/zope/testbrowser/testing.py
D zope.testbrowser/tags/3.5.1/src/zope/testbrowser/tests.py
A zope.testbrowser/tags/3.5.1/src/zope/testbrowser/tests.py
-=-
Copied: zope.testbrowser/tags/3.5.1 (from rev 91902, zope.testbrowser/trunk)
Property changes on: zope.testbrowser/tags/3.5.1
___________________________________________________________________
Name: svn:ignore
+ bin
build
dist
lib
setup.cfg
develop-eggs
eggs
parts
.installed.cfg
Name: svn:mergeinfo
+
Deleted: zope.testbrowser/tags/3.5.1/CHANGES.txt
===================================================================
--- zope.testbrowser/trunk/CHANGES.txt 2008-10-08 09:30:09 UTC (rev 91902)
+++ zope.testbrowser/tags/3.5.1/CHANGES.txt 2008-10-10 16:57:17 UTC (rev 92000)
@@ -1,69 +0,0 @@
-=======
-CHANGES
-=======
-
-
-3.5.0 (unreleased)
-------------------
-
-- Provide a work around for a mechanize/urllib2 bug in creating request
- objects that won't handle fragment URLs correctly.
-
-- Added a zope.testbrowser.testing.Browser.post method that allows
- tests to supply a body and a content type. This is handy for
- testing Ajax requests with non-form input (e.g. JSON).
-
-- Remove vendor import of mechanize.
-
-- Fix bug that caused HTTP exception tracebacks to differ between version 3.4.0
- and 3.4.1.
-
-- Workaround for bug in Python Cookie.SimpleCookie when handling unicode
- strings.
-
-- Fix bug introduced in 3.4.1 that created incompatible tracebacks in doctests.
- This necessitated adding a patched mechanize to the source tree; patches have
- been sent to the mechanize project.
-
-- Fix https://bugs.launchpad.net/bugs/149517 by adding zope.interface and
- zope.schema as real dependencies
-
-- Fix browser.getLink documentation that was not updated since the last API
- modification.
-
-- Move tests for fixed bugs to a separate file.
-
-- Removed non-functional and undocumented code intended to help test servers
- using virtual hosting.
-
-
-3.4.2 (2007-10-31)
-------------------
-
-- Resolve ``ZopeSecurityPolicy`` deprecation warning.
-
-
-3.4.1 (2007-09-01)
-------------------
-
-* Updated to mechanize 0.1.7b and ClientForm 0.2.7. These are now
- pulled in via egg dependencies.
-
-* ``zope.testbrowser`` now works on Python 2.5.
-
-
-3.4.0 (2007-06-04)
-------------------
-
-* Added the ability to suppress raising exceptions on HTTP errors
- (``raiseHttpErrors`` attribute).
-
-* Made the tests more resilient to HTTP header formatting changes with
- the REnormalizer.
-
-
-3.4.0a1 (2007-04-22)
---------------------
-
-Initial release as a separate project, corresponds to zope.testbrowser
-from Zope 3.4.0a1
Copied: zope.testbrowser/tags/3.5.1/CHANGES.txt (from rev 91999, zope.testbrowser/trunk/CHANGES.txt)
===================================================================
--- zope.testbrowser/tags/3.5.1/CHANGES.txt (rev 0)
+++ zope.testbrowser/tags/3.5.1/CHANGES.txt 2008-10-10 16:57:17 UTC (rev 92000)
@@ -0,0 +1,74 @@
+=======
+CHANGES
+=======
+
+3.5.1 (2008-10-10)
+------------------
+
+- Provide a work around for a mechanize/urllib2 bug on Python 2.6
+ missing 'timeout' attribute on 'Request' base class.
+
+- Provide a work around for a mechanize/urllib2 bug in creating request
+ objects that won't handle fragment URLs correctly.
+
+3.5.0 (2008-03-30)
+------------------
+
+- Added a zope.testbrowser.testing.Browser.post method that allows
+ tests to supply a body and a content type. This is handy for
+ testing Ajax requests with non-form input (e.g. JSON).
+
+- Remove vendor import of mechanize.
+
+- Fix bug that caused HTTP exception tracebacks to differ between version 3.4.0
+ and 3.4.1.
+
+- Workaround for bug in Python Cookie.SimpleCookie when handling unicode
+ strings.
+
+- Fix bug introduced in 3.4.1 that created incompatible tracebacks in doctests.
+ This necessitated adding a patched mechanize to the source tree; patches have
+ been sent to the mechanize project.
+
+- Fix https://bugs.launchpad.net/bugs/149517 by adding zope.interface and
+ zope.schema as real dependencies
+
+- Fix browser.getLink documentation that was not updated since the last API
+ modification.
+
+- Move tests for fixed bugs to a separate file.
+
+- Removed non-functional and undocumented code intended to help test servers
+ using virtual hosting.
+
+
+3.4.2 (2007-10-31)
+------------------
+
+- Resolve ``ZopeSecurityPolicy`` deprecation warning.
+
+
+3.4.1 (2007-09-01)
+------------------
+
+* Updated to mechanize 0.1.7b and ClientForm 0.2.7. These are now
+ pulled in via egg dependencies.
+
+* ``zope.testbrowser`` now works on Python 2.5.
+
+
+3.4.0 (2007-06-04)
+------------------
+
+* Added the ability to suppress raising exceptions on HTTP errors
+ (``raiseHttpErrors`` attribute).
+
+* Made the tests more resilient to HTTP header formatting changes with
+ the REnormalizer.
+
+
+3.4.0a1 (2007-04-22)
+--------------------
+
+Initial release as a separate project, corresponds to zope.testbrowser
+from Zope 3.4.0a1
Modified: zope.testbrowser/tags/3.5.1/bootstrap.py
===================================================================
--- zope.testbrowser/trunk/bootstrap.py 2008-10-08 09:30:09 UTC (rev 91902)
+++ zope.testbrowser/tags/3.5.1/bootstrap.py 2008-10-10 16:57:17 UTC (rev 92000)
@@ -17,7 +17,7 @@
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
-$Id: bootstrap.py 72703 2007-02-20 11:49:26Z jim $
+$Id$
"""
import os, shutil, sys, tempfile, urllib2
Deleted: zope.testbrowser/tags/3.5.1/buildout.cfg
===================================================================
--- zope.testbrowser/trunk/buildout.cfg 2008-10-08 09:30:09 UTC (rev 91902)
+++ zope.testbrowser/tags/3.5.1/buildout.cfg 2008-10-10 16:57:17 UTC (rev 92000)
@@ -1,24 +0,0 @@
-[buildout]
-develop = .
-parts = test interpreter
-index = http://download.zope.org/simple
-extends = http://download.zope.org/zope3.4/versions.cfg
-versions = versions
-allow-picked-versions = false
-use-dependency-links = false
-
-[versions]
-zope.testbrowser =
-zope.publisher = 3.5.1
-zope.app.publication = 3.4.2
-
-[test]
-recipe = zc.recipe.testrunner
-defaults = ['--tests-pattern', '^f?tests$']
-eggs = zope.testbrowser [test]
-
-[interpreter]
-recipe = zc.recipe.egg
-eggs = zope.testbrowser
- mechanize
-interpreter = py
Copied: zope.testbrowser/tags/3.5.1/buildout.cfg (from rev 91989, zope.testbrowser/trunk/buildout.cfg)
===================================================================
--- zope.testbrowser/tags/3.5.1/buildout.cfg (rev 0)
+++ zope.testbrowser/tags/3.5.1/buildout.cfg 2008-10-10 16:57:17 UTC (rev 92000)
@@ -0,0 +1,26 @@
+[buildout]
+develop = .
+parts = test interpreter
+index = http://download.zope.org/simple
+extends = http://download.zope.org/zope3.4/versions.cfg
+versions = versions
+allow-picked-versions = false
+use-dependency-links = false
+
+[versions]
+mechanize = 0.1.9
+setuptools = 0.6c9
+zope.testbrowser =
+zope.publisher = 3.5.1
+zope.app.publication = 3.4.2
+
+[test]
+recipe = zc.recipe.testrunner
+defaults = ['--tests-pattern', '^f?tests$']
+eggs = zope.testbrowser [test]
+
+[interpreter]
+recipe = zc.recipe.egg
+eggs = zope.testbrowser
+ mechanize
+interpreter = py
Deleted: zope.testbrowser/tags/3.5.1/setup.py
===================================================================
--- zope.testbrowser/trunk/setup.py 2008-10-08 09:30:09 UTC (rev 91902)
+++ zope.testbrowser/tags/3.5.1/setup.py 2008-10-10 16:57:17 UTC (rev 92000)
@@ -1,70 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Setup for zope.testbrowser package
-
-$Id$
-"""
-import os
-from setuptools import setup, find_packages
-
-long_description = (
- '.. contents::\n\n'
- + open('README.txt').read()
- + '\n\n'
- + open(os.path.join('src', 'zope', 'testbrowser', 'README.txt')).read()
- + '\n\n'
- + open('CHANGES.txt').read()
- )
-
-setup(
- name = 'zope.testbrowser',
- version = '3.5.0dev',
- url = 'http://pypi.python.org/pypi/zope.testbrowser',
- license = 'ZPL 2.1',
- description = 'Programmable browser for functional black-box tests',
- author = 'Zope Corporation and Contributors',
- author_email = 'zope3-dev at zope.org',
- long_description = long_description,
- classifiers=[
- 'Environment :: Web Environment',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Zope Public License',
- 'Programming Language :: Python',
- 'Topic :: Software Development :: Testing',
- 'Topic :: Internet :: WWW/HTTP',
- ],
-
- packages = find_packages('src'),
- package_dir = {'': 'src'},
- namespace_packages = ['zope',],
- tests_require = ['zope.testing'],
- install_requires = [
- 'ClientForm >= 0.2.8',
- 'mechanize',
- 'setuptools',
- 'zope.interface',
- 'zope.schema',
- ],
- extras_require = dict(
- test = [
- 'zope.app.component',
- 'zope.app.folder',
- 'zope.app.securitypolicy',
- 'zope.app.testing',
- 'zope.app.zcmlfiles',
- ],
- ),
- include_package_data = True,
- zip_safe = False,
- )
Copied: zope.testbrowser/tags/3.5.1/setup.py (from rev 91989, zope.testbrowser/trunk/setup.py)
===================================================================
--- zope.testbrowser/tags/3.5.1/setup.py (rev 0)
+++ zope.testbrowser/tags/3.5.1/setup.py 2008-10-10 16:57:17 UTC (rev 92000)
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Setup for zope.testbrowser package
+
+$Id$
+"""
+import os
+from setuptools import setup, find_packages
+
+long_description = (
+ '.. contents::\n\n'
+ + open('README.txt').read()
+ + '\n\n'
+ + open(os.path.join('src', 'zope', 'testbrowser', 'README.txt')).read()
+ + '\n\n'
+ + open('CHANGES.txt').read()
+ )
+
+setup(
+ name = 'zope.testbrowser',
+ version = '3.5.1dev',
+ url = 'http://pypi.python.org/pypi/zope.testbrowser',
+ license = 'ZPL 2.1',
+ description = 'Programmable browser for functional black-box tests',
+ author = 'Zope Corporation and Contributors',
+ author_email = 'zope3-dev at zope.org',
+ long_description = long_description,
+ classifiers=[
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Topic :: Software Development :: Testing',
+ 'Topic :: Internet :: WWW/HTTP',
+ ],
+
+ packages = find_packages('src'),
+ package_dir = {'': 'src'},
+ namespace_packages = ['zope',],
+ tests_require = ['zope.testing'],
+ install_requires = [
+ 'ClientForm >= 0.2.8',
+ 'mechanize',
+ 'setuptools',
+ 'zope.interface',
+ 'zope.schema',
+ ],
+ extras_require = dict(
+ test = [
+ 'zope.app.component',
+ 'zope.app.folder',
+ 'zope.app.securitypolicy',
+ 'zope.app.testing',
+ 'zope.app.zcmlfiles',
+ ],
+ ),
+ include_package_data = True,
+ zip_safe = False,
+ )
Deleted: zope.testbrowser/tags/3.5.1/src/zope/testbrowser/testing.py
===================================================================
--- zope.testbrowser/trunk/src/zope/testbrowser/testing.py 2008-10-08 09:30:09 UTC (rev 91902)
+++ zope.testbrowser/tags/3.5.1/src/zope/testbrowser/testing.py 2008-10-10 16:57:17 UTC (rev 92000)
@@ -1,172 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2005 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Zope 3-specific testing code
-
-$Id$
-"""
-import re
-import sys
-import unittest
-import httplib
-import urllib2
-from cStringIO import StringIO
-
-import mechanize
-
-import transaction
-from zope.testbrowser import browser
-from zope.testing import renormalizing, doctest
-
-from zope.app.testing import functional
-from zope.app.folder.folder import Folder
-from zope.app.component.site import LocalSiteManager
-
-class PublisherConnection(object):
- """A ``urllib2`` compatible connection obejct."""
-
- def __init__(self, host):
- self.caller = functional.HTTPCaller()
- self.host = host
-
- def set_debuglevel(self, level):
- pass
-
- def _quote(self, url):
- # the publisher expects to be able to split on whitespace, so we have
- # to make sure there is none in the URL
- return url.replace(' ', '%20')
-
- def request(self, method, url, body=None, headers=None):
- """Send a request to the publisher.
-
- The response will be stored in ``self.response``.
- """
- if body is None:
- body = ''
-
- if url == '':
- url = '/'
-
- url = self._quote(url)
- # Extract the handle_error option header
- if sys.version_info >= (2,5):
- handle_errors_key = 'X-Zope-Handle-Errors'
- else:
- handle_errors_key = 'X-zope-handle-errors'
- handle_errors = headers.get(handle_errors_key, True)
- if handle_errors_key in headers:
- del headers[handle_errors_key]
-
- # Construct the headers.
- header_chunks = []
- if headers is not None:
- for header in headers.items():
- header_chunks.append('%s: %s' % header)
- headers = '\n'.join(header_chunks) + '\n'
- else:
- headers = ''
-
- # Construct the full HTTP request string, since that is what the
- # ``HTTPCaller`` wants.
- request_string = (method + ' ' + url + ' HTTP/1.1\n'
- + headers + '\n' + body)
- self.response = self.caller(request_string, handle_errors)
-
- def getresponse(self):
- """Return a ``urllib2`` compatible response.
-
- The goal of ths method is to convert the Zope Publisher's reseponse to
- a ``urllib2`` compatible response, which is also understood by
- mechanize.
- """
- real_response = self.response._response
- status = real_response.getStatus()
- reason = real_response._reason # XXX add a getReason method
-
- headers = real_response.getHeaders()
- headers.sort()
- headers.insert(0, ('Status', real_response.getStatusString()))
- headers = '\r\n'.join('%s: %s' % h for h in headers)
- content = real_response.consumeBody()
- return PublisherResponse(content, headers, status, reason)
-
-
-class PublisherResponse(object):
- """``urllib2`` compatible response object."""
-
- def __init__(self, content, headers, status, reason):
- self.content = content
- self.status = status
- self.reason = reason
- self.msg = httplib.HTTPMessage(StringIO(headers), 0)
- self.content_as_file = StringIO(self.content)
-
- def read(self, amt=None):
- return self.content_as_file.read(amt)
-
- def close(self):
- """To overcome changes in urllib2 and socket in python2.5"""
- pass
-
-
-class PublisherHTTPHandler(urllib2.HTTPHandler):
- """Special HTTP handler to use the Zope Publisher."""
-
- def http_request(self, req):
- # look at data and set content type
- if req.has_data():
- data = req.get_data()
- if isinstance(data, dict):
- req.add_data(data['body'])
- req.add_unredirected_header('Content-type',
- data['content-type'])
- return urllib2.AbstractHTTPHandler.do_request_(self, req)
-
- def http_open(self, req):
- """Open an HTTP connection having a ``urllib2`` request."""
- # Here we connect to the publisher.
- return self.do_open(PublisherConnection, req)
-
-
-class PublisherMechanizeBrowser(mechanize.Browser):
- """Special ``mechanize`` browser using the Zope Publisher HTTP handler."""
-
- default_schemes = ['http']
- default_others = ['_http_error', '_http_request_upgrade',
- '_http_default_error']
- default_features = ['_redirect', '_cookies', '_referer', '_refresh',
- '_equiv', '_basicauth', '_digestauth']
-
- def __init__(self, *args, **kws):
- inherited_handlers = ['_unknown', '_http_error',
- '_http_request_upgrade', '_http_default_error', '_basicauth',
- '_digestauth', '_redirect', '_cookies', '_referer',
- '_refresh', '_equiv', '_gzip']
-
- self.handler_classes = {"http": PublisherHTTPHandler}
- for name in inherited_handlers:
- self.handler_classes[name] = mechanize.Browser.handler_classes[name]
-
- kws['request_class'] = kws.get('request_class',
- mechanize._request.Request)
-
- mechanize.Browser.__init__(self, *args, **kws)
-
-
-class Browser(browser.Browser):
- """A Zope `testbrowser` Browser that uses the Zope Publisher."""
-
- def __init__(self, url=None):
- mech_browser = PublisherMechanizeBrowser()
- super(Browser, self).__init__(url=url, mech_browser=mech_browser)
Copied: zope.testbrowser/tags/3.5.1/src/zope/testbrowser/testing.py (from rev 91989, zope.testbrowser/trunk/src/zope/testbrowser/testing.py)
===================================================================
--- zope.testbrowser/tags/3.5.1/src/zope/testbrowser/testing.py (rev 0)
+++ zope.testbrowser/tags/3.5.1/src/zope/testbrowser/testing.py 2008-10-10 16:57:17 UTC (rev 92000)
@@ -0,0 +1,177 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Zope 3-specific testing code
+
+$Id$
+"""
+import re
+import sys
+import socket
+import unittest
+import httplib
+import urllib2
+from cStringIO import StringIO
+
+import mechanize
+
+import transaction
+from zope.testbrowser import browser
+from zope.testing import renormalizing, doctest
+
+from zope.app.testing import functional
+from zope.app.folder.folder import Folder
+from zope.app.component.site import LocalSiteManager
+
+class PublisherConnection(object):
+ """A ``urllib2`` compatible connection obejct."""
+
+ def __init__(self, host, timeout=None):
+ self.caller = functional.HTTPCaller()
+ self.host = host
+
+ def set_debuglevel(self, level):
+ pass
+
+ def _quote(self, url):
+ # the publisher expects to be able to split on whitespace, so we have
+ # to make sure there is none in the URL
+ return url.replace(' ', '%20')
+
+ def request(self, method, url, body=None, headers=None):
+ """Send a request to the publisher.
+
+ The response will be stored in ``self.response``.
+ """
+ if body is None:
+ body = ''
+
+ if url == '':
+ url = '/'
+
+ url = self._quote(url)
+ # Extract the handle_error option header
+ if sys.version_info >= (2,5):
+ handle_errors_key = 'X-Zope-Handle-Errors'
+ else:
+ handle_errors_key = 'X-zope-handle-errors'
+ handle_errors = headers.get(handle_errors_key, True)
+ if handle_errors_key in headers:
+ del headers[handle_errors_key]
+
+ # Construct the headers.
+ header_chunks = []
+ if headers is not None:
+ for header in headers.items():
+ header_chunks.append('%s: %s' % header)
+ headers = '\n'.join(header_chunks) + '\n'
+ else:
+ headers = ''
+
+ # Construct the full HTTP request string, since that is what the
+ # ``HTTPCaller`` wants.
+ request_string = (method + ' ' + url + ' HTTP/1.1\n'
+ + headers + '\n' + body)
+ self.response = self.caller(request_string, handle_errors)
+
+ def getresponse(self):
+ """Return a ``urllib2`` compatible response.
+
+ The goal of ths method is to convert the Zope Publisher's reseponse to
+ a ``urllib2`` compatible response, which is also understood by
+ mechanize.
+ """
+ real_response = self.response._response
+ status = real_response.getStatus()
+ reason = real_response._reason # XXX add a getReason method
+
+ headers = real_response.getHeaders()
+ headers.sort()
+ headers.insert(0, ('Status', real_response.getStatusString()))
+ headers = '\r\n'.join('%s: %s' % h for h in headers)
+ content = real_response.consumeBody()
+ return PublisherResponse(content, headers, status, reason)
+
+
+class PublisherResponse(object):
+ """``urllib2`` compatible response object."""
+
+ def __init__(self, content, headers, status, reason):
+ self.content = content
+ self.status = status
+ self.reason = reason
+ self.msg = httplib.HTTPMessage(StringIO(headers), 0)
+ self.content_as_file = StringIO(self.content)
+
+ def read(self, amt=None):
+ return self.content_as_file.read(amt)
+
+ def close(self):
+ """To overcome changes in urllib2 and socket in python2.5"""
+ pass
+
+
+class PublisherHTTPHandler(urllib2.HTTPHandler):
+ """Special HTTP handler to use the Zope Publisher."""
+
+ def http_request(self, req):
+ # look at data and set content type
+ if req.has_data():
+ data = req.get_data()
+ if isinstance(data, dict):
+ req.add_data(data['body'])
+ req.add_unredirected_header('Content-type',
+ data['content-type'])
+ return urllib2.AbstractHTTPHandler.do_request_(self, req)
+
+ def http_open(self, req):
+ """Open an HTTP connection having a ``urllib2`` request."""
+ # Here we connect to the publisher.
+ if sys.version_info > (2, 6) and not hasattr(req, 'timeout'):
+ # Workaround mechanize incompatibility with Python
+ # 2.6. See: LP #280334
+ req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
+ return self.do_open(PublisherConnection, req)
+
+
+class PublisherMechanizeBrowser(mechanize.Browser):
+ """Special ``mechanize`` browser using the Zope Publisher HTTP handler."""
+
+ default_schemes = ['http']
+ default_others = ['_http_error', '_http_request_upgrade',
+ '_http_default_error']
+ default_features = ['_redirect', '_cookies', '_referer', '_refresh',
+ '_equiv', '_basicauth', '_digestauth']
+
+ def __init__(self, *args, **kws):
+ inherited_handlers = ['_unknown', '_http_error',
+ '_http_request_upgrade', '_http_default_error', '_basicauth',
+ '_digestauth', '_redirect', '_cookies', '_referer',
+ '_refresh', '_equiv', '_gzip']
+
+ self.handler_classes = {"http": PublisherHTTPHandler}
+ for name in inherited_handlers:
+ self.handler_classes[name] = mechanize.Browser.handler_classes[name]
+
+ kws['request_class'] = kws.get('request_class',
+ mechanize._request.Request)
+
+ mechanize.Browser.__init__(self, *args, **kws)
+
+
+class Browser(browser.Browser):
+ """A Zope `testbrowser` Browser that uses the Zope Publisher."""
+
+ def __init__(self, url=None):
+ mech_browser = PublisherMechanizeBrowser()
+ super(Browser, self).__init__(url=url, mech_browser=mech_browser)
Deleted: zope.testbrowser/tags/3.5.1/src/zope/testbrowser/tests.py
===================================================================
--- zope.testbrowser/trunk/src/zope/testbrowser/tests.py 2008-10-08 09:30:09 UTC (rev 91902)
+++ zope.testbrowser/tags/3.5.1/src/zope/testbrowser/tests.py 2008-10-10 16:57:17 UTC (rev 92000)
@@ -1,403 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Real test for file-upload and beginning of a better internal test framework
-
-$Id$
-"""
-
-from cStringIO import StringIO
-from zope.app.testing import functional
-from zope.app.testing.functional import FunctionalDocFileSuite
-from zope.testbrowser import browser
-from zope.testing import doctest
-from zope.testing import renormalizing, doctest
-import httplib
-import mechanize
-import os
-import re
-import unittest
-import unittest
-import urllib2
-
-
-def set_next_response(body, headers=None, status='200', reason='OK'):
- global next_response_body
- global next_response_headers
- global next_response_status
- global next_response_reason
- if headers is None:
- headers = (
- 'Content-Type: text/html\r\n'
- 'Content-Length: %s\r\n'
- % len(body)
- )
- next_response_body = body
- next_response_headers = headers
- next_response_status = status
- next_response_reason = reason
-
-
-class FauxConnection(object):
- """A ``urllib2`` compatible connection object."""
-
- def __init__(self, host):
- pass
-
- def set_debuglevel(self, level):
- pass
-
- def _quote(self, url):
- # the publisher expects to be able to split on whitespace, so we have
- # to make sure there is none in the URL
- return url.replace(' ', '%20')
-
-
- def request(self, method, url, body=None, headers=None):
- if body is None:
- body = ''
-
- if url == '':
- url = '/'
-
- url = self._quote(url)
-
- # Construct the headers.
- header_chunks = []
- if headers is not None:
- for header in headers.items():
- header_chunks.append('%s: %s' % header)
- headers = '\n'.join(header_chunks) + '\n'
- else:
- headers = ''
-
- # Construct the full HTTP request string, since that is what the
- # ``HTTPCaller`` wants.
- request_string = (method + ' ' + url + ' HTTP/1.1\n'
- + headers + '\n' + body)
-
- print request_string.replace('\r', '')
-
- def getresponse(self):
- """Return a ``urllib2`` compatible response.
-
- The goal of this method is to convert the Zope Publisher's response to
- a ``urllib2`` compatible response, which is also understood by
- mechanize.
- """
- return FauxResponse(next_response_body,
- next_response_headers,
- next_response_status,
- next_response_reason,
- )
-
-class FauxResponse(object):
-
- def __init__(self, content, headers, status, reason):
- self.content = content
- self.status = status
- self.reason = reason
- self.msg = httplib.HTTPMessage(StringIO(headers), 0)
- self.content_as_file = StringIO(self.content)
-
- def read(self, amt=None):
- return self.content_as_file.read(amt)
-
- def close(self):
- """To overcome changes in urllib2 and socket in python2.5"""
- pass
-
-
-class FauxHTTPHandler(urllib2.HTTPHandler):
-
- http_request = urllib2.AbstractHTTPHandler.do_request_
-
- def http_open(self, req):
- """Open an HTTP connection having a ``urllib2`` request."""
- # Here we connect to the publisher.
- return self.do_open(FauxConnection, req)
-
-
-class FauxMechanizeBrowser(mechanize.Browser):
-
- handler_classes = {
- # scheme handlers
- "http": FauxHTTPHandler,
-
- "_http_error": mechanize.HTTPErrorProcessor,
- "_http_request_upgrade": mechanize.HTTPRequestUpgradeProcessor,
- "_http_default_error": urllib2.HTTPDefaultErrorHandler,
-
- # feature handlers
- "_authen": urllib2.HTTPBasicAuthHandler,
- "_redirect": mechanize.HTTPRedirectHandler,
- "_cookies": mechanize.HTTPCookieProcessor,
- "_refresh": mechanize.HTTPRefreshProcessor,
- "_referer": mechanize.Browser.handler_classes['_referer'],
- "_equiv": mechanize.HTTPEquivProcessor,
- }
-
- default_schemes = ["http"]
- default_others = ["_http_error", "_http_request_upgrade",
- "_http_default_error"]
- default_features = ["_authen", "_redirect", "_cookies"]
-
-
-class Browser(browser.Browser):
-
- def __init__(self, url=None):
- mech_browser = FauxMechanizeBrowser()
- super(Browser, self).__init__(url=url, mech_browser=mech_browser)
-
- def open(self, body, headers=None, status=200, reason='OK'):
- set_next_response(body, headers, status, reason)
- browser.Browser.open(self, 'http://localhost/')
-
-def test_submit_duplicate_name():
- """
-
-This test was inspired by bug #723 as testbrowser would pick up the wrong
-button when having the same name twice in a form.
-
- >>> browser = Browser()
-
-When given a form with two submit buttons that have the same name:
-
- >>> browser.open('''\
- ... <html><body>
- ... <form action="." method="post" enctype="multipart/form-data">
- ... <input type="submit" name="submit_me" value="GOOD" />
- ... <input type="submit" name="submit_me" value="BAD" />
- ... </form></body></html>
- ... ''') # doctest: +ELLIPSIS
- GET / HTTP/1.1
- ...
-
-We can specify the second button through it's label/value:
-
- >>> browser.getControl('BAD')
- <SubmitControl name='submit_me' type='submit'>
- >>> browser.getControl('BAD').value
- 'BAD'
- >>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF
- POST / HTTP/1.1
- Content-length: 176
- Connection: close
- Content-type: multipart/form-data; boundary=---------------------------100167997466992641913031254
- Host: localhost
- User-agent: Python-urllib/2.4
- <BLANKLINE>
- -----------------------------100167997466992641913031254
- Content-disposition: form-data; name="submit_me"
- <BLANKLINE>
- BAD
- -----------------------------100167997466992641913031254--
- <BLANKLINE>
-
-This also works if the labels have whitespace around them (this tests a
-regression caused by the original fix for the above):
-
- >>> browser.open('''\
- ... <html><body>
- ... <form action="." method="post" enctype="multipart/form-data">
- ... <input type="submit" name="submit_me" value=" GOOD " />
- ... <input type="submit" name="submit_me" value=" BAD " />
- ... </form></body></html>
- ... ''') # doctest: +ELLIPSIS
- GET / HTTP/1.1
- ...
- >>> browser.getControl('BAD')
- <SubmitControl name='submit_me' type='submit'>
- >>> browser.getControl('BAD').value
- ' BAD '
- >>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF
- POST / HTTP/1.1
- Content-length: 176
- Connection: close
- Content-type: multipart/form-data; boundary=---------------------------100167997466992641913031254
- Host: localhost
- User-agent: Python-urllib/2.4
- <BLANKLINE>
- -----------------------------100167997466992641913031254
- Content-disposition: form-data; name="submit_me"
- <BLANKLINE>
- BAD
- -----------------------------100167997466992641913031254--
- <BLANKLINE>
-
-"""
-
-def test_file_upload():
- """
-
- >>> browser = Browser()
-
-When given a form with a file-upload
-
- >>> browser.open('''\
- ... <html><body>
- ... <form action="." method="post" enctype="multipart/form-data">
- ... <input name="foo" type="file" />
- ... <input type="submit" value="OK" />
- ... </form></body></html>
- ... ''') # doctest: +ELLIPSIS
- GET / HTTP/1.1
- ...
-
-Fill in the form value using add_file:
-
- >>> browser.getControl(name='foo').add_file(
- ... StringIO('sample_data'), 'text/foo', 'x.foo')
- >>> browser.getControl('OK').click()
- POST / HTTP/1.1
- Content-length: 173
- Connection: close
- Content-type: multipart/form-data; boundary=127.0.0.11000318041146699896411
- Host: localhost
- User-agent: Python-urllib/2.99
- <BLANKLINE>
- --127.0.0.11000318041146699896411
- Content-disposition: form-data; name="foo"; filename="x.foo"
- Content-type: text/foo
- <BLANKLINE>
- sample_data
- --127.0.0.11000318041146699896411--
- <BLANKLINE>
-
-You can pass a string to add_file:
-
-
- >>> browser.getControl(name='foo').add_file(
- ... 'blah blah blah', 'text/blah', 'x.blah')
- >>> browser.getControl('OK').click()
- POST / HTTP/1.1
- Content-length: 178
- Connection: close
- Content-type: multipart/form-data; boundary=127.0.0.11000318541146700017052
- Host: localhost
- User-agent: Python-urllib/2.98
- <BLANKLINE>
- --127.0.0.11000318541146700017052
- Content-disposition: form-data; name="foo"; filename="x.blah"
- Content-type: text/blah
- <BLANKLINE>
- blah blah blah
- --127.0.0.11000318541146700017052--
- <BLANKLINE>
-
-
- """
-
-
-def test_strip_linebreaks_from_textarea(self):
- """
-
- >>> browser = Browser()
-
-According to http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.1 line break
-immediately after start tags or immediately before end tags must be ignored,
-but real browsers only ignore a line break after a start tag. So if we give
-the following form:
-
- >>> browser.open('''
- ... <html><body>
- ... <form action="." method="post" enctype="multipart/form-data">
- ... <textarea name="textarea">
- ... Foo
- ... </textarea>
- ... </form></body></html>
- ... ''') # doctest: +ELLIPSIS
- GET / HTTP/1.1
- ...
-
-The value of the textarea won't contain the first line break:
-
- >>> browser.getControl(name='textarea').value
- 'Foo\\n'
-
-Of course, if we add line breaks, so that there are now two line breaks
-after the start tag, the textarea value will start and end with a line break.
-
- >>> browser.open('''
- ... <html><body>
- ... <form action="." method="post" enctype="multipart/form-data">
- ... <textarea name="textarea">
- ...
- ... Foo
- ... </textarea>
- ... </form></body></html>
- ... ''') # doctest: +ELLIPSIS
- GET / HTTP/1.1
- ...
-
- >>> browser.getControl(name='textarea').value
- '\\nFoo\\n'
-
-Also, if there is some other whitespace after the start tag, it will be preserved.
-
- >>> browser.open('''
- ... <html><body>
- ... <form action="." method="post" enctype="multipart/form-data">
- ... <textarea name="textarea"> Foo </textarea>
- ... </form></body></html>
- ... ''') # doctest: +ELLIPSIS
- GET / HTTP/1.1
- ...
-
- >>> browser.getControl(name='textarea').value
- ' Foo '
- """
-
-class win32CRLFtransformer(object):
- def sub(self, replacement, text):
- return text.replace(r'\r','')
-
-checker = renormalizing.RENormalizing([
- (re.compile(r'^--\S+\.\S+\.\S+', re.M), '-'*30),
- (re.compile(r'boundary=\S+\.\S+\.\S+'), 'boundary='+'-'*30),
- (re.compile(r'^---{10}.*', re.M), '-'*30),
- (re.compile(r'boundary=-{10}.*'), 'boundary='+'-'*30),
- (re.compile(r'User-agent:\s+\S+'), 'User-agent: Python-urllib/2.4'),
- (re.compile(r'HTTP_USER_AGENT:\s+\S+'), 'HTTP_USER_AGENT: Python-urllib/2.4'),
- (re.compile(r'Content-[Ll]ength:.*'), 'Content-Length: 123'),
- (re.compile(r'Status: 200.*'), 'Status: 200 OK'),
- (win32CRLFtransformer(), None),
- (re.compile(r'User-Agent: Python-urllib/2.5'), 'User-agent: Python-urllib/2.4'),
- (re.compile(r'Host: localhost'), 'Connection: close'),
- (re.compile(r'Content-Type: '), 'Content-type: '),
- ])
-
-TestBrowserLayer = functional.ZCMLLayer(
- os.path.join(os.path.split(__file__)[0], 'ftests/ftesting.zcml'),
- __name__, 'TestBrowserLayer', allow_teardown=True)
-
-def test_suite():
- flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
-
- readme = FunctionalDocFileSuite('README.txt', optionflags=flags,
- checker=checker)
- readme.layer = TestBrowserLayer
-
- fixed_bugs = FunctionalDocFileSuite('fixed-bugs.txt', optionflags=flags)
- fixed_bugs.layer = TestBrowserLayer
-
- wire = FunctionalDocFileSuite('over_the_wire.txt', optionflags=flags)
- wire.level = 2
- wire.layer = TestBrowserLayer
-
- this_file = doctest.DocTestSuite(checker=checker)
-
- return unittest.TestSuite((this_file, readme, fixed_bugs, wire))
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
Copied: zope.testbrowser/tags/3.5.1/src/zope/testbrowser/tests.py (from rev 91989, zope.testbrowser/trunk/src/zope/testbrowser/tests.py)
===================================================================
--- zope.testbrowser/tags/3.5.1/src/zope/testbrowser/tests.py (rev 0)
+++ zope.testbrowser/tags/3.5.1/src/zope/testbrowser/tests.py 2008-10-10 16:57:17 UTC (rev 92000)
@@ -0,0 +1,411 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Real test for file-upload and beginning of a better internal test framework
+
+$Id$
+"""
+
+from cStringIO import StringIO
+from zope.app.testing import functional
+from zope.app.testing.functional import FunctionalDocFileSuite
+from zope.testbrowser import browser
+from zope.testing import doctest
+from zope.testing import renormalizing, doctest
+import httplib
+import mechanize
+import os
+import re
+import sys
+import socket
+import unittest
+import unittest
+import urllib2
+
+
+def set_next_response(body, headers=None, status='200', reason='OK'):
+ global next_response_body
+ global next_response_headers
+ global next_response_status
+ global next_response_reason
+ if headers is None:
+ headers = (
+ 'Content-Type: text/html\r\n'
+ 'Content-Length: %s\r\n'
+ % len(body)
+ )
+ next_response_body = body
+ next_response_headers = headers
+ next_response_status = status
+ next_response_reason = reason
+
+
+class FauxConnection(object):
+ """A ``urllib2`` compatible connection object."""
+
+ def __init__(self, host, timeout=None):
+ pass
+
+ def set_debuglevel(self, level):
+ pass
+
+ def _quote(self, url):
+ # the publisher expects to be able to split on whitespace, so we have
+ # to make sure there is none in the URL
+ return url.replace(' ', '%20')
+
+
+ def request(self, method, url, body=None, headers=None):
+ if body is None:
+ body = ''
+
+ if url == '':
+ url = '/'
+
+ url = self._quote(url)
+
+ # Construct the headers.
+ header_chunks = []
+ if headers is not None:
+ for header in headers.items():
+ header_chunks.append('%s: %s' % header)
+ headers = '\n'.join(header_chunks) + '\n'
+ else:
+ headers = ''
+
+ # Construct the full HTTP request string, since that is what the
+ # ``HTTPCaller`` wants.
+ request_string = (method + ' ' + url + ' HTTP/1.1\n'
+ + headers + '\n' + body)
+
+ print request_string.replace('\r', '')
+
+ def getresponse(self):
+ """Return a ``urllib2`` compatible response.
+
+ The goal of this method is to convert the Zope Publisher's response to
+ a ``urllib2`` compatible response, which is also understood by
+ mechanize.
+ """
+ return FauxResponse(next_response_body,
+ next_response_headers,
+ next_response_status,
+ next_response_reason,
+ )
+
+class FauxResponse(object):
+
+ def __init__(self, content, headers, status, reason):
+ self.content = content
+ self.status = status
+ self.reason = reason
+ self.msg = httplib.HTTPMessage(StringIO(headers), 0)
+ self.content_as_file = StringIO(self.content)
+
+ def read(self, amt=None):
+ return self.content_as_file.read(amt)
+
+ def close(self):
+ """To overcome changes in urllib2 and socket in python2.5"""
+ pass
+
+
+class FauxHTTPHandler(urllib2.HTTPHandler):
+
+ http_request = urllib2.AbstractHTTPHandler.do_request_
+
+ def http_open(self, req):
+ """Open an HTTP connection having a ``urllib2`` request."""
+ # Here we connect to the publisher.
+
+ if sys.version_info > (2, 6) and not hasattr(req, 'timeout'):
+ # Workaround mechanize incompatibility with Python
+ # 2.6. See: LP #280334
+ req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
+ return self.do_open(FauxConnection, req)
+
+
+class FauxMechanizeBrowser(mechanize.Browser):
+
+ handler_classes = {
+ # scheme handlers
+ "http": FauxHTTPHandler,
+
+ "_http_error": mechanize.HTTPErrorProcessor,
+ "_http_request_upgrade": mechanize.HTTPRequestUpgradeProcessor,
+ "_http_default_error": urllib2.HTTPDefaultErrorHandler,
+
+ # feature handlers
+ "_authen": urllib2.HTTPBasicAuthHandler,
+ "_redirect": mechanize.HTTPRedirectHandler,
+ "_cookies": mechanize.HTTPCookieProcessor,
+ "_refresh": mechanize.HTTPRefreshProcessor,
+ "_referer": mechanize.Browser.handler_classes['_referer'],
+ "_equiv": mechanize.HTTPEquivProcessor,
+ }
+
+ default_schemes = ["http"]
+ default_others = ["_http_error", "_http_request_upgrade",
+ "_http_default_error"]
+ default_features = ["_authen", "_redirect", "_cookies"]
+
+
+class Browser(browser.Browser):
+
+ def __init__(self, url=None):
+ mech_browser = FauxMechanizeBrowser()
+ super(Browser, self).__init__(url=url, mech_browser=mech_browser)
+
+ def open(self, body, headers=None, status=200, reason='OK'):
+ set_next_response(body, headers, status, reason)
+ browser.Browser.open(self, 'http://localhost/')
+
+def test_submit_duplicate_name():
+ """
+
+This test was inspired by bug #723 as testbrowser would pick up the wrong
+button when having the same name twice in a form.
+
+ >>> browser = Browser()
+
+When given a form with two submit buttons that have the same name:
+
+ >>> browser.open('''\
+ ... <html><body>
+ ... <form action="." method="post" enctype="multipart/form-data">
+ ... <input type="submit" name="submit_me" value="GOOD" />
+ ... <input type="submit" name="submit_me" value="BAD" />
+ ... </form></body></html>
+ ... ''') # doctest: +ELLIPSIS
+ GET / HTTP/1.1
+ ...
+
+We can specify the second button through it's label/value:
+
+ >>> browser.getControl('BAD')
+ <SubmitControl name='submit_me' type='submit'>
+ >>> browser.getControl('BAD').value
+ 'BAD'
+ >>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF
+ POST / HTTP/1.1
+ Content-length: 176
+ Connection: close
+ Content-type: multipart/form-data; boundary=---------------------------100167997466992641913031254
+ Host: localhost
+ User-agent: Python-urllib/2.4
+ <BLANKLINE>
+ -----------------------------100167997466992641913031254
+ Content-disposition: form-data; name="submit_me"
+ <BLANKLINE>
+ BAD
+ -----------------------------100167997466992641913031254--
+ <BLANKLINE>
+
+This also works if the labels have whitespace around them (this tests a
+regression caused by the original fix for the above):
+
+ >>> browser.open('''\
+ ... <html><body>
+ ... <form action="." method="post" enctype="multipart/form-data">
+ ... <input type="submit" name="submit_me" value=" GOOD " />
+ ... <input type="submit" name="submit_me" value=" BAD " />
+ ... </form></body></html>
+ ... ''') # doctest: +ELLIPSIS
+ GET / HTTP/1.1
+ ...
+ >>> browser.getControl('BAD')
+ <SubmitControl name='submit_me' type='submit'>
+ >>> browser.getControl('BAD').value
+ ' BAD '
+ >>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF
+ POST / HTTP/1.1
+ Content-length: 176
+ Connection: close
+ Content-type: multipart/form-data; boundary=---------------------------100167997466992641913031254
+ Host: localhost
+ User-agent: Python-urllib/2.4
+ <BLANKLINE>
+ -----------------------------100167997466992641913031254
+ Content-disposition: form-data; name="submit_me"
+ <BLANKLINE>
+ BAD
+ -----------------------------100167997466992641913031254--
+ <BLANKLINE>
+
+"""
+
+def test_file_upload():
+ """
+
+ >>> browser = Browser()
+
+When given a form with a file-upload
+
+ >>> browser.open('''\
+ ... <html><body>
+ ... <form action="." method="post" enctype="multipart/form-data">
+ ... <input name="foo" type="file" />
+ ... <input type="submit" value="OK" />
+ ... </form></body></html>
+ ... ''') # doctest: +ELLIPSIS
+ GET / HTTP/1.1
+ ...
+
+Fill in the form value using add_file:
+
+ >>> browser.getControl(name='foo').add_file(
+ ... StringIO('sample_data'), 'text/foo', 'x.foo')
+ >>> browser.getControl('OK').click()
+ POST / HTTP/1.1
+ Content-length: 173
+ Connection: close
+ Content-type: multipart/form-data; boundary=127.0.0.11000318041146699896411
+ Host: localhost
+ User-agent: Python-urllib/2.99
+ <BLANKLINE>
+ --127.0.0.11000318041146699896411
+ Content-disposition: form-data; name="foo"; filename="x.foo"
+ Content-type: text/foo
+ <BLANKLINE>
+ sample_data
+ --127.0.0.11000318041146699896411--
+ <BLANKLINE>
+
+You can pass a string to add_file:
+
+
+ >>> browser.getControl(name='foo').add_file(
+ ... 'blah blah blah', 'text/blah', 'x.blah')
+ >>> browser.getControl('OK').click()
+ POST / HTTP/1.1
+ Content-length: 178
+ Connection: close
+ Content-type: multipart/form-data; boundary=127.0.0.11000318541146700017052
+ Host: localhost
+ User-agent: Python-urllib/2.98
+ <BLANKLINE>
+ --127.0.0.11000318541146700017052
+ Content-disposition: form-data; name="foo"; filename="x.blah"
+ Content-type: text/blah
+ <BLANKLINE>
+ blah blah blah
+ --127.0.0.11000318541146700017052--
+ <BLANKLINE>
+
+
+ """
+
+
+def test_strip_linebreaks_from_textarea(self):
+ """
+
+ >>> browser = Browser()
+
+According to http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.1 line break
+immediately after start tags or immediately before end tags must be ignored,
+but real browsers only ignore a line break after a start tag. So if we give
+the following form:
+
+ >>> browser.open('''
+ ... <html><body>
+ ... <form action="." method="post" enctype="multipart/form-data">
+ ... <textarea name="textarea">
+ ... Foo
+ ... </textarea>
+ ... </form></body></html>
+ ... ''') # doctest: +ELLIPSIS
+ GET / HTTP/1.1
+ ...
+
+The value of the textarea won't contain the first line break:
+
+ >>> browser.getControl(name='textarea').value
+ 'Foo\\n'
+
+Of course, if we add line breaks, so that there are now two line breaks
+after the start tag, the textarea value will start and end with a line break.
+
+ >>> browser.open('''
+ ... <html><body>
+ ... <form action="." method="post" enctype="multipart/form-data">
+ ... <textarea name="textarea">
+ ...
+ ... Foo
+ ... </textarea>
+ ... </form></body></html>
+ ... ''') # doctest: +ELLIPSIS
+ GET / HTTP/1.1
+ ...
+
+ >>> browser.getControl(name='textarea').value
+ '\\nFoo\\n'
+
+Also, if there is some other whitespace after the start tag, it will be preserved.
+
+ >>> browser.open('''
+ ... <html><body>
+ ... <form action="." method="post" enctype="multipart/form-data">
+ ... <textarea name="textarea"> Foo </textarea>
+ ... </form></body></html>
+ ... ''') # doctest: +ELLIPSIS
+ GET / HTTP/1.1
+ ...
+
+ >>> browser.getControl(name='textarea').value
+ ' Foo '
+ """
+
+class win32CRLFtransformer(object):
+ def sub(self, replacement, text):
+ return text.replace(r'\r','')
+
+checker = renormalizing.RENormalizing([
+ (re.compile(r'^--\S+\.\S+\.\S+', re.M), '-'*30),
+ (re.compile(r'boundary=\S+\.\S+\.\S+'), 'boundary='+'-'*30),
+ (re.compile(r'^---{10}.*', re.M), '-'*30),
+ (re.compile(r'boundary=-{10}.*'), 'boundary='+'-'*30),
+ (re.compile(r'User-agent:\s+\S+'), 'User-agent: Python-urllib/2.4'),
+ (re.compile(r'HTTP_USER_AGENT:\s+\S+'), 'HTTP_USER_AGENT: Python-urllib/2.4'),
+ (re.compile(r'Content-[Ll]ength:.*'), 'Content-Length: 123'),
+ (re.compile(r'Status: 200.*'), 'Status: 200 OK'),
+ (win32CRLFtransformer(), None),
+ (re.compile(r'User-Agent: Python-urllib/2.5'), 'User-agent: Python-urllib/2.4'),
+ (re.compile(r'User-Agent: Python-urllib/2.6'), 'User-agent: Python-urllib/2.4'),
+ (re.compile(r'Host: localhost'), 'Connection: close'),
+ (re.compile(r'Content-Type: '), 'Content-type: '),
+ ])
+
+TestBrowserLayer = functional.ZCMLLayer(
+ os.path.join(os.path.split(__file__)[0], 'ftests/ftesting.zcml'),
+ __name__, 'TestBrowserLayer', allow_teardown=True)
+
+def test_suite():
+ flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
+
+ readme = FunctionalDocFileSuite('README.txt', optionflags=flags,
+ checker=checker)
+ readme.layer = TestBrowserLayer
+
+ fixed_bugs = FunctionalDocFileSuite('fixed-bugs.txt', optionflags=flags)
+ fixed_bugs.layer = TestBrowserLayer
+
+ wire = FunctionalDocFileSuite('over_the_wire.txt', optionflags=flags)
+ wire.level = 2
+ wire.layer = TestBrowserLayer
+
+ this_file = doctest.DocTestSuite(checker=checker)
+
+ return unittest.TestSuite((this_file, readme, fixed_bugs, wire))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
More information about the Checkins
mailing list