[Checkins] SVN: Zope/branches/tseaver-fix_wsgi/src/ZPublisher/ More PEP8; coverage for retry, status, cookie, header, and base APIs.

Tres Seaver tseaver at palladion.com
Mon Dec 21 16:35:21 EST 2009


Log message for revision 106837:
  More PEP8;  coverage for retry, status,  cookie, header, and base APIs.

Changed:
  U   Zope/branches/tseaver-fix_wsgi/src/ZPublisher/HTTPResponse.py
  U   Zope/branches/tseaver-fix_wsgi/src/ZPublisher/tests/testHTTPResponse.py

-=-
Modified: Zope/branches/tseaver-fix_wsgi/src/ZPublisher/HTTPResponse.py
===================================================================
--- Zope/branches/tseaver-fix_wsgi/src/ZPublisher/HTTPResponse.py	2009-12-21 20:56:35 UTC (rev 106836)
+++ Zope/branches/tseaver-fix_wsgi/src/ZPublisher/HTTPResponse.py	2009-12-21 21:35:21 UTC (rev 106837)
@@ -200,20 +200,6 @@
         # think that that's all that is ever passed.
         return self.__class__(stdout=self.stdout, stderr=self.stderr)
 
-    _shutdown_flag = None
-    def _requestShutdown(self, exitCode=0):
-        """ Request that the server shut down with exitCode after fulfilling
-           the current request.
-        """
-        import ZServer
-        ZServer.exit_code = exitCode
-        self._shutdown_flag = 1
-
-    def _shutdownRequested(self):
-        """ Returns true if this request requested a server shutdown.
-        """
-        return self._shutdown_flag is not None
-
     def setStatus(self, status, reason=None, lock=None):
         """ Set the HTTP status code of the response
         
@@ -252,42 +238,184 @@
         if lock:
              self._locked_status = 1
 
+    def setCookie(self, name, value, **kw):
+        """ Set an HTTP cookie.
+
+        The response will include an HTTP header that sets a cookie on
+        cookie-enabled browsers with a key "name" and value
+        "value".
+        
+        This value overwrites any previously set value for the
+        cookie in the Response object.
+        """
+        name = str(name)
+        value = str(value)
+
+        cookies = self.cookies
+        if cookies.has_key(name):
+            cookie = cookies[name]
+        else:
+            cookie = cookies[name] = {}
+        for k, v in kw.items():
+            cookie[k] = v
+        cookie['value'] = value
+
+    def appendCookie(self, name, value):
+        """ Set an HTTP cookie.
+        
+        Returns an HTTP header that sets a cookie on cookie-enabled
+        browsers with a key "name" and value "value". If a value for the
+        cookie has previously been set in the response object, the new
+        value is appended to the old one separated by a colon.
+        """
+        name = str(name)
+        value = str(value)
+
+        cookies = self.cookies
+        if cookies.has_key(name):
+            cookie = cookies[name]
+        else:
+            cookie = cookies[name] = {}
+        if cookie.has_key('value'):
+            cookie['value'] = '%s:%s' % (cookie['value'], value)
+        else:
+            cookie['value'] = value
+
+    def expireCookie(self, name, **kw):
+        """ Clear an HTTP cookie.
+
+        The response will include an HTTP header that will remove the cookie
+        corresponding to "name" on the client, if one exists. This is
+        accomplished by sending a new cookie with an expiration date
+        that has already passed. Note that some clients require a path
+        to be specified - this path must exactly match the path given
+        when creating the cookie. The path can be specified as a keyword
+        argument.
+        """
+        name = str(name)
+
+        d = kw.copy()
+        if 'value' in d:
+            d.pop('value')
+        d['max_age'] = 0
+        d['expires'] = 'Wed, 31-Dec-97 23:59:59 GMT'
+
+        self.setCookie(name, value='deleted', **d)
+
+    def getHeader(self, name, literal=0):
+        """ Get a previously set header value.
+
+        Return the value associated with a HTTP return header, or
+        None if no such header has been set in the response
+        yet.
+        
+        If the 'literal' flag is true, preserve the case of the header name;
+        otherwise lower-case the header name before looking up the value.
+        """
+        key = literal and name or name.lower()
+        return self.headers.get(key, None)
+
     def setHeader(self, name, value, literal=0, scrubbed=False):
-        '''\
-        Sets an HTTP return header "name" with value "value", clearing
-        the previous value set for the header, if one exists. If the
-        literal flag is true, the case of the header name is preserved,
-        otherwise the header name will be lowercased.'''
+        """ Set an HTTP return header on the response.
+        
+        Replay any existing value set for the header.
+        
+        If the 'literal' flag is true, preserve the case of the header name;
+        otherwise the header name will be lowercased.
+
+        'scrubbed' is for internal use, to indicate that another API has
+        already removed any CRLF from the name and value.
+        """
         if not scrubbed:
             name, value = _scrubHeader(name, value)
         key = name.lower()
-        if key == 'set-cookie':
+        # The following is crazy, given that we have APIs for cookies.
+        # Special behavior will go away in Zope 2.13
+        if key == 'set-cookie':  
             self.accumulated_headers.append((name, value))
         else:
             name = literal and name or key
             self.headers[name] = value
 
-    def getHeader(self, name, literal=0):
-        '''\
-        Get a header value
+    def appendHeader(self, name, value, delimiter=","):
+        """ Append a value to an HTTP return header.
 
-        Returns the value associated with a HTTP return header, or
-        "None" if no such header has been set in the response
-        yet. If the literal flag is true, the case of the header name is
-        preserved, otherwise the header name will be lowercased.'''
-        key = name.lower()
-        name = literal and name or key
-        return self.headers.get(name, None)
+        Set an HTTP return header "name" with value "value",
+        appending it following a comma if there was a previous value
+        set for the header.
 
+        'name' is always lowercased before use.
+        """
+        name, value = _scrubHeader(name, value)
+        name = name.lower()
+
+        headers = self.headers
+        if headers.has_key(name):
+            h = headers[name]
+            h = "%s%s\r\n\t%s" % (h, delimiter, value)
+        else:
+            h = value
+        self.setHeader(name,h, scrubbed=True)
+
     def addHeader(self, name, value):
-        '''\
-        Set a new HTTP return header with the given value, while retaining
-        any previously set headers with the same name.'''
+        """ Set a new HTTP return header with the given value,
+        
+        Retain any previously set headers with the same name.
+
+        Note that this API appneds to the 'accumulated_headers' attribute;
+        it does not update the 'headers' mapping.
+        """
         name, value = _scrubHeader(name, value)
         self.accumulated_headers.append((name, value))
 
     __setitem__ = setHeader
 
+    def setBase(self, base):
+        """Set the base URL for the returned document.
+
+        If base is None, set to the empty string.
+
+        If base is not None, ensure that it has a trailing slach.
+        """
+        if base is None:
+            base = ''
+        elif not base.endswith('/'):
+            base = base + '/'
+
+        self.base = str(base)
+
+    def insertBase(self,
+                   base_re_search=re.compile('(<base.*?>)',re.I).search
+                   ):
+
+        # Only insert a base tag if content appears to be html.
+        content_type = self.headers.get('content-type', '').split(';')[0]
+        if content_type and (content_type != 'text/html'):
+            return
+
+        if self.base:
+            body = self.body
+            if body:
+                match = start_of_header_search(body)
+                if match is not None:
+                    index = match.start(0) + len(match.group(0))
+                    ibase = base_re_search(body)
+                    if ibase is None:
+                        self.body = ('%s\n<base href="%s" />\n%s' %
+                                   (body[:index], escape(self.base, 1),
+                                    body[index:]))
+                        self.setHeader('content-length', len(self.body))
+
+    def isHTML(self, s):
+        s = s.lstrip()
+        # Note that the string can be big, so s.lower().startswith() is more
+        # expensive than s[:n].lower().
+        if (s[:6].lower() == '<html>' or s[:14].lower() == '<!doctype html'):
+            return 1
+        if s.find('</') > 0:
+            return 1
+        return 0
+
     def setBody(self, body, title='', is_error=0,
                 bogus_str_search=re.compile(" [a-fA-F0-9]+>$").search,
                 latin1_alias_match=re.compile(
@@ -460,6 +588,23 @@
 
         return self.use_HTTP_content_compression
 
+    # The following two methods are part of a private protocol with the
+    # publisher for handling fatal import errors and TTW shutdown requests.
+    _shutdown_flag = None
+    def _requestShutdown(self, exitCode=0):
+        """ Request that the server shut down with exitCode after fulfilling
+           the current request.
+        """
+        import ZServer
+        ZServer.exit_code = exitCode
+        self._shutdown_flag = 1
+
+    def _shutdownRequested(self):
+        """ Returns true if this request requested a server shutdown.
+        """
+        return self._shutdown_flag is not None
+
+
     def _encode_unicode(self,body,
                         charset_re=re.compile(r'(?:application|text)/[-+0-9a-z]+\s*;\s*' +
                                               r'charset=([-_0-9a-z]+' +
@@ -496,127 +641,6 @@
         body = fix_xml_preamble(body, default_encoding)
         return body
 
-    def setBase(self, base):
-        """Set the base URL for the returned document.
-
-        If base is None, or the document already has a base, do nothing.
-        """
-        if base is None:
-            base = ''
-        elif not base.endswith('/'):
-            base = base + '/'
-        self.base = str(base)
-
-    def insertBase(self,
-                   base_re_search=re.compile('(<base.*?>)',re.I).search
-                   ):
-
-        # Only insert a base tag if content appears to be html.
-        content_type = self.headers.get('content-type', '').split(';')[0]
-        if content_type and (content_type != 'text/html'):
-            return
-
-        if self.base:
-            body = self.body
-            if body:
-                match = start_of_header_search(body)
-                if match is not None:
-                    index = match.start(0) + len(match.group(0))
-                    ibase = base_re_search(body)
-                    if ibase is None:
-                        self.body = ('%s\n<base href="%s" />\n%s' %
-                                   (body[:index], escape(self.base, 1),
-                                    body[index:]))
-                        self.setHeader('content-length', len(self.body))
-
-    def appendCookie(self, name, value):
-        '''\
-        Returns an HTTP header that sets a cookie on cookie-enabled
-        browsers with a key "name" and value "value". If a value for the
-        cookie has previously been set in the response object, the new
-        value is appended to the old one separated by a colon. '''
-
-        name = str(name)
-        value = str(value)
-
-        cookies = self.cookies
-        if cookies.has_key(name):
-            cookie = cookies[name]
-        else:
-            cookie = cookies[name] = {}
-        if cookie.has_key('value'):
-            cookie['value'] = '%s:%s' % (cookie['value'], value)
-        else:
-            cookie['value'] = value
-
-    def expireCookie(self, name, **kw):
-        '''\
-        Cause an HTTP cookie to be removed from the browser
-
-        The response will include an HTTP header that will remove the cookie
-        corresponding to "name" on the client, if one exists. This is
-        accomplished by sending a new cookie with an expiration date
-        that has already passed. Note that some clients require a path
-        to be specified - this path must exactly match the path given
-        when creating the cookie. The path can be specified as a keyword
-        argument.
-        '''
-        name = str(name)
-
-        d = kw.copy()
-        d['max_age'] = 0
-        d['expires'] = 'Wed, 31-Dec-97 23:59:59 GMT'
-        apply(HTTPResponse.setCookie, (self, name, 'deleted'), d)
-
-    def setCookie(self,name,value,**kw):
-        '''\
-        Set an HTTP cookie on the browser
-
-        The response will include an HTTP header that sets a cookie on
-        cookie-enabled browsers with a key "name" and value
-        "value". This overwrites any previously set value for the
-        cookie in the Response object.
-        '''
-        name = str(name)
-        value = str(value)
-
-        cookies = self.cookies
-        if cookies.has_key(name):
-            cookie = cookies[name]
-        else:
-            cookie = cookies[name] = {}
-        for k, v in kw.items():
-            cookie[k] = v
-        cookie['value'] = value
-
-    def appendHeader(self, name, value, delimiter=","):
-        '''\
-        Append a value to a header.
-
-        Sets an HTTP return header "name" with value "value",
-        appending it following a comma if there was a previous value
-        set for the header. '''
-        name, value = _scrubHeader(name, value)
-        name = name.lower()
-
-        headers = self.headers
-        if headers.has_key(name):
-            h = headers[name]
-            h = "%s%s\r\n\t%s" % (h,delimiter,value)
-        else:
-            h = value
-        self.setHeader(name,h, scrubbed=True)
-
-    def isHTML(self, s):
-        s = s.lstrip()
-        # Note that the string can be big, so s.lower().startswith() is more
-        # expensive than s[:n].lower().
-        if (s[:6].lower() == '<html>' or s[:14].lower() == '<!doctype html'):
-            return 1
-        if s.find('</') > 0:
-            return 1
-        return 0
-
     # deprecated
     def quoteHTML(self, text):
         return escape(text, 1)

Modified: Zope/branches/tseaver-fix_wsgi/src/ZPublisher/tests/testHTTPResponse.py
===================================================================
--- Zope/branches/tseaver-fix_wsgi/src/ZPublisher/tests/testHTTPResponse.py	2009-12-21 20:56:35 UTC (rev 106836)
+++ Zope/branches/tseaver-fix_wsgi/src/ZPublisher/tests/testHTTPResponse.py	2009-12-21 21:35:21 UTC (rev 106837)
@@ -58,14 +58,6 @@
         self.assertEqual(response.headers,
                          {'status': '401 Unauthorized'}) # XXX WTF?
 
-    def test_retry(self):
-        STDOUT, STDERR = object(), object()
-        response = self._makeOne(stdout=STDOUT, stderr=STDERR)
-        cloned = response.retry()
-        self.failUnless(isinstance(cloned, self._getTargetClass()))
-        self.failUnless(cloned.stdout is STDOUT)
-        self.failUnless(cloned.stderr is STDERR)
-
     def test_ctor_charset_no_content_type_header(self):
         response = self._makeOne(body='foo')
         self.assertEqual(response.headers.get('content-type'),
@@ -122,49 +114,86 @@
                                             'text/xml; charset=iso-8859-15'})
         self.assertEqual(response.body, xml)
 
+    def test_retry(self):
+        STDOUT, STDERR = object(), object()
+        response = self._makeOne(stdout=STDOUT, stderr=STDERR)
+        cloned = response.retry()
+        self.failUnless(isinstance(cloned, self._getTargetClass()))
+        self.failUnless(cloned.stdout is STDOUT)
+        self.failUnless(cloned.stderr is STDERR)
+
+    def test_setStatus_code(self):
+        response = self._makeOne()
+        response.setStatus(400)
+        self.assertEqual(response.status, 400)
+        self.assertEqual(response.errmsg, 'Bad Request')
+
+    def test_setStatus_errmsg(self):
+        response = self._makeOne()
+        response.setStatus('Bad Request')
+        self.assertEqual(response.status, 400)
+        self.assertEqual(response.errmsg, 'Bad Request')
+
     def test_setStatus_BadRequest(self):
         from zExceptions import BadRequest
         response = self._makeOne()
         response.setStatus(BadRequest)
         self.assertEqual(response.status, 400)
+        self.assertEqual(response.errmsg, 'Bad Request')
 
-    def test_setStatus_Unauthorized(self):
+    def test_setStatus_Unauthorized_exception(self):
         from zExceptions import Unauthorized
         response = self._makeOne()
         response.setStatus(Unauthorized)
         self.assertEqual(response.status, 401)
+        self.assertEqual(response.errmsg, 'Unauthorized')
 
-    def test_setStatus_Forbidden(self):
+    def test_setStatus_Forbidden_exception(self):
         from zExceptions import Forbidden
         response = self._makeOne()
         response.setStatus(Forbidden)
         self.assertEqual(response.status, 403)
+        self.assertEqual(response.errmsg, 'Forbidden')
 
-    def test_setStatus_NotFound(self):
+    def test_setStatus_NotFound_exception(self):
         from zExceptions import NotFound
         response = self._makeOne()
         response.setStatus(NotFound)
         self.assertEqual(response.status, 404)
+        self.assertEqual(response.errmsg, 'Not Found')
 
-    def test_setStatus_ResourceLockedError(self):
+    def test_setStatus_ResourceLockedError_exception(self):
         response = self._makeOne()
         from webdav.Lockable import ResourceLockedError
         response.setStatus(ResourceLockedError)
         self.assertEqual(response.status, 423)
+        self.assertEqual(response.errmsg, 'Locked')
 
-    def test_setStatus_InternalError(self):
+    def test_setStatus_InternalError_exception(self):
         from zExceptions import InternalError
         response = self._makeOne()
         response.setStatus(InternalError)
         self.assertEqual(response.status, 500)
+        self.assertEqual(response.errmsg, 'Internal Server Error')
 
-    def test_setCookie_no_attrs(self):
+    def test_setCookie_no_existing(self):
         response = self._makeOne()
         response.setCookie('foo', 'bar')
         cookie = response.cookies.get('foo', None)
         self.assertEqual(len(cookie), 1)
         self.assertEqual(cookie.get('value'), 'bar')
 
+    def test_setCookie_w_existing(self):
+        response = self._makeOne()
+        response.setCookie('foo', 'bar')
+        response.setCookie('foo', 'baz')
+        cookie = response.cookies.get('foo', None)
+        self.assertEqual(len(cookie), 1)
+        self.assertEqual(cookie.get('value'), 'baz')
+
+    def test_setCookie_no_attrs(self):
+        response = self._makeOne()
+        response.setCookie('foo', 'bar')
         cookies = response._cookie_list()
         self.assertEqual(len(cookies), 1)
         self.assertEqual(cookies[0], 'Set-Cookie: foo="bar"')
@@ -268,6 +297,22 @@
         self.assertEqual(len(cookie_list), 1)
         self.assertEqual(cookie_list[0], 'Set-Cookie: foo="bar"')
 
+    def test_appendCookie_w_existing(self):
+        response = self._makeOne()
+        response.setCookie('foo', 'bar', path='/')
+        response.appendCookie('foo', 'baz')
+        cookie = response.cookies.get('foo', None)
+        self.failUnless(cookie)
+        self.assertEqual(cookie.get('value'), 'bar:baz')
+        self.assertEqual(cookie.get('path'), '/')
+
+    def test_appendCookie_no_existing(self):
+        response = self._makeOne()
+        response.appendCookie('foo', 'baz')
+        cookie = response.cookies.get('foo', None)
+        self.failUnless(cookie)
+        self.assertEqual(cookie.get('value'), 'baz')
+
     def test_expireCookie(self):
         response = self._makeOne()
         response.expireCookie('foo', path='/')
@@ -289,24 +334,22 @@
         self.assertEqual(cookie.get('max_age'), 0)
         self.assertEqual(cookie.get('path'), '/')
 
-    def test_appendCookie(self):
+    def test_getHeader_nonesuch(self):
         response = self._makeOne()
-        response.setCookie('foo', 'bar', path='/')
-        response.appendCookie('foo', 'baz')
-        cookie = response.cookies.get('foo', None)
-        self.failUnless(cookie)
-        self.assertEqual(cookie.get('value'), 'bar:baz')
-        self.assertEqual(cookie.get('path'), '/')
+        self.assertEqual(response.getHeader('nonesuch'), None)
 
-    def test_appendHeader(self):
-        response = self._makeOne()
-        response.setHeader('foo', 'bar')
-        response.appendHeader('foo', 'foo')
-        self.assertEqual(response.headers.get('foo'), 'bar,\r\n\tfoo')
-        response.setHeader('xxx', 'bar')
-        response.appendHeader('XXX', 'foo')
-        self.assertEqual(response.headers.get('xxx'), 'bar,\r\n\tfoo')
+    def test_getHeader_existing(self):
+        response = self._makeOne(headers={'foo': 'bar'})
+        self.assertEqual(response.getHeader('foo'), 'bar')
 
+    def test_getHeader_existing_not_literal(self):
+        response = self._makeOne(headers={'foo': 'bar'})
+        self.assertEqual(response.getHeader('Foo'), 'bar')
+
+    def test_getHeader_existing_w_literal(self):
+        response = self._makeOne(headers={'Foo': 'Bar'})
+        self.assertEqual(response.getHeader('Foo', literal=True), 'Bar')
+
     def test_setHeader(self):
         response = self._makeOne()
         response.setHeader('foo', 'bar')
@@ -324,22 +367,6 @@
         self.assertEqual(response.getHeader('SPAM', literal=True), 'eggs')
         self.assertEqual(response.getHeader('spam'), None)
 
-    def test_addHeader_drops_CRLF(self):
-        # RFC2616 disallows CRLF in a header value.
-        response = self._makeOne()
-        response.addHeader('Location',
-                           'http://www.ietf.org/rfc/\r\nrfc2616.txt')
-        self.assertEqual(response.accumulated_headers,
-                         [('Location', 'http://www.ietf.org/rfc/rfc2616.txt')])
-
-    def test_appendHeader_drops_CRLF(self):
-        # RFC2616 disallows CRLF in a header value.
-        response = self._makeOne()
-        response.appendHeader('Location',
-                               'http://www.ietf.org/rfc/\r\nrfc2616.txt')
-        self.assertEqual(response.headers['location'],
-                         'http://www.ietf.org/rfc/rfc2616.txt')
-
     def test_setHeader_drops_CRLF(self):
         # RFC2616 disallows CRLF in a header value.
         response = self._makeOne()
@@ -348,8 +375,19 @@
         self.assertEqual(response.headers['location'],
                          'http://www.ietf.org/rfc/rfc2616.txt')
 
+    def test_setHeader_Set_Cookie_special_case(self):
+        # This is crazy, given that we have APIs for cookies.  Special
+        # behavior will go away in Zope 2.13
+        response = self._makeOne()
+        response.setHeader('Set-Cookie', 'foo="bar"')
+        self.assertEqual(response.getHeader('Set-Cookie'), None)
+        self.assertEqual(response.accumulated_headers,
+                         [('Set-Cookie', 'foo="bar"')])
+
     def test_setHeader_drops_CRLF_when_accumulating(self):
         # RFC2616 disallows CRLF in a header value.
+        # This is crazy, given that we have APIs for cookies.  Special
+        # behavior will go away in Zope 2.13
         response = self._makeOne()
         response.setHeader('Set-Cookie', 'allowed="OK"')
         response.setHeader('Set-Cookie',
@@ -359,6 +397,110 @@
                          ('Set-Cookie',
                           'violation="http://www.ietf.org/rfc/rfc2616.txt"')])
 
+    def test_appendHeader_no_existing(self):
+        response = self._makeOne()
+        response.appendHeader('foo', 'foo')
+        self.assertEqual(response.headers.get('foo'), 'foo')
+
+    def test_appendHeader_no_existing_case_insensative(self):
+        response = self._makeOne()
+        response.appendHeader('Foo', 'foo')
+        self.assertEqual(response.headers.get('foo'), 'foo')
+
+    def test_appendHeader_w_existing(self):
+        response = self._makeOne()
+        response.setHeader('foo', 'bar')
+        response.appendHeader('foo', 'foo')
+        self.assertEqual(response.headers.get('foo'), 'bar,\r\n\tfoo')
+
+    def test_appendHeader_w_existing_case_insenstative(self):
+        response = self._makeOne()
+        response.setHeader('xxx', 'bar')
+        response.appendHeader('XXX', 'foo')
+        self.assertEqual(response.headers.get('xxx'), 'bar,\r\n\tfoo')
+
+    def test_appendHeader_drops_CRLF(self):
+        # RFC2616 disallows CRLF in a header value.
+        response = self._makeOne()
+        response.appendHeader('Location',
+                               'http://www.ietf.org/rfc/\r\nrfc2616.txt')
+        self.assertEqual(response.headers['location'],
+                         'http://www.ietf.org/rfc/rfc2616.txt')
+
+    def test_addHeader_is_case_sensitive(self):
+        response = self._makeOne()
+        response.addHeader('Location', 'http://www.ietf.org/rfc/rfc2616.txt')
+        self.assertEqual(response.accumulated_headers,
+                         [('Location', 'http://www.ietf.org/rfc/rfc2616.txt')])
+
+    def test_addHeader_drops_CRLF(self):
+        # RFC2616 disallows CRLF in a header value.
+        response = self._makeOne()
+        response.addHeader('Location',
+                           'http://www.ietf.org/rfc/\r\nrfc2616.txt')
+        self.assertEqual(response.accumulated_headers,
+                         [('Location', 'http://www.ietf.org/rfc/rfc2616.txt')])
+
+    def test_setBase_None(self):
+        response = self._makeOne()
+        response.base = 'BEFORE'
+        response.setBase(None)
+        self.assertEqual(response.base, '')
+
+    def test_setBase_no_trailing_path(self):
+        response = self._makeOne()
+        response.setBase('foo')
+        self.assertEqual(response.base, 'foo/')
+
+    def test_setBase_w_trailing_path(self):
+        response = self._makeOne()
+        response.setBase('foo/')
+        self.assertEqual(response.base, 'foo/')
+
+    def test_insertBase_not_HTML_no_change(self):
+        response = self._makeOne()
+        response.setHeader('Content-Type', 'application/pdf')
+        response.setHeader('Content-Length', 8)
+        response.body = 'BLAHBLAH'
+        response.insertBase()
+        self.assertEqual(response.body, 'BLAHBLAH')
+        self.assertEqual(response.getHeader('Content-Length'), '8')
+
+    def test_insertBase_HTML_no_base_w_head_not_munged(self):
+        HTML = '<html><head></head><body></body></html>'
+        response = self._makeOne()
+        response.setHeader('Content-Type', 'text/html')
+        response.setHeader('Content-Length', len(HTML))
+        response.body = HTML
+        response.insertBase()
+        self.assertEqual(response.body, HTML)
+        self.assertEqual(response.getHeader('Content-Length'), str(len(HTML)))
+
+    def test_insertBase_HTML_w_base_no_head_not_munged(self):
+        HTML = '<html><body></body></html>'
+        response = self._makeOne()
+        response.setHeader('Content-Type', 'text/html')
+        response.setHeader('Content-Length', len(HTML))
+        response.body = HTML
+        response.insertBase()
+        self.assertEqual(response.body, HTML)
+        self.assertEqual(response.getHeader('Content-Length'), str(len(HTML)))
+
+    def test_insertBase_HTML_w_base_w_head_munged(self):
+        HTML = '<html><head></head><body></body></html>'
+        MUNGED = ('<html><head>\n'
+                  '<base href="http://example.com/base/" />\n'
+                  '</head><body></body></html>')
+        response = self._makeOne()
+        response.setHeader('Content-Type', 'text/html')
+        response.setHeader('Content-Length', 8)
+        response.body = HTML
+        response.setBase('http://example.com/base/')
+        response.insertBase()
+        self.assertEqual(response.body, MUNGED)
+        self.assertEqual(response.getHeader('Content-Length'),
+                         str(len(MUNGED)))
+
     def test_setBody_compression_vary(self):
         # Vary header should be added here
         response = self._makeOne()



More information about the checkins mailing list