123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- """
- HTTP errors.
- """
- from __future__ import division, absolute_import
- import re
- import sys
- import traceback
- from twisted.trial import unittest
- from twisted.python.compat import nativeString, _PY3
- from twisted.web import error
- from twisted.web.template import Tag
- class CodeToMessageTests(unittest.TestCase):
- """
- L{_codeToMessages} inverts L{_responses.RESPONSES}
- """
- def test_validCode(self):
- m = error._codeToMessage(b"302")
- self.assertEqual(m, b"Found")
- def test_invalidCode(self):
- m = error._codeToMessage(b"987")
- self.assertEqual(m, None)
- def test_nonintegerCode(self):
- m = error._codeToMessage(b"InvalidCode")
- self.assertEqual(m, None)
- class ErrorTests(unittest.TestCase):
- """
- Tests for how L{Error} attributes are initialized.
- """
- def test_noMessageValidStatus(self):
- """
- If no C{message} argument is passed to the L{Error} constructor and the
- C{code} argument is a valid HTTP status code, C{code} is mapped to a
- descriptive string to which C{message} is assigned.
- """
- e = error.Error(b"200")
- self.assertEqual(e.message, b"OK")
- def test_noMessageInvalidStatus(self):
- """
- If no C{message} argument is passed to the L{Error} constructor and
- C{code} isn't a valid HTTP status code, C{message} stays L{None}.
- """
- e = error.Error(b"InvalidCode")
- self.assertEqual(e.message, None)
- def test_messageExists(self):
- """
- If a C{message} argument is passed to the L{Error} constructor, the
- C{message} isn't affected by the value of C{status}.
- """
- e = error.Error(b"200", b"My own message")
- self.assertEqual(e.message, b"My own message")
- def test_str(self):
- """
- C{str()} on an L{Error} returns the code and message it was
- instantiated with.
- """
- # Bytestring status
- e = error.Error(b"200", b"OK")
- self.assertEqual(str(e), "200 OK")
- # int status
- e = error.Error(200, b"OK")
- self.assertEqual(str(e), "200 OK")
- class PageRedirectTests(unittest.TestCase):
- """
- Tests for how L{PageRedirect} attributes are initialized.
- """
- def test_noMessageValidStatus(self):
- """
- If no C{message} argument is passed to the L{PageRedirect} constructor
- and the C{code} argument is a valid HTTP status code, C{code} is mapped
- to a descriptive string to which C{message} is assigned.
- """
- e = error.PageRedirect(b"200", location=b"/foo")
- self.assertEqual(e.message, b"OK to /foo")
- def test_noMessageValidStatusNoLocation(self):
- """
- If no C{message} argument is passed to the L{PageRedirect} constructor
- and C{location} is also empty and the C{code} argument is a valid HTTP
- status code, C{code} is mapped to a descriptive string to which
- C{message} is assigned without trying to include an empty location.
- """
- e = error.PageRedirect(b"200")
- self.assertEqual(e.message, b"OK")
- def test_noMessageInvalidStatusLocationExists(self):
- """
- If no C{message} argument is passed to the L{PageRedirect} constructor
- and C{code} isn't a valid HTTP status code, C{message} stays L{None}.
- """
- e = error.PageRedirect(b"InvalidCode", location=b"/foo")
- self.assertEqual(e.message, None)
- def test_messageExistsLocationExists(self):
- """
- If a C{message} argument is passed to the L{PageRedirect} constructor,
- the C{message} isn't affected by the value of C{status}.
- """
- e = error.PageRedirect(b"200", b"My own message", location=b"/foo")
- self.assertEqual(e.message, b"My own message to /foo")
- def test_messageExistsNoLocation(self):
- """
- If a C{message} argument is passed to the L{PageRedirect} constructor
- and no location is provided, C{message} doesn't try to include the
- empty location.
- """
- e = error.PageRedirect(b"200", b"My own message")
- self.assertEqual(e.message, b"My own message")
- class InfiniteRedirectionTests(unittest.TestCase):
- """
- Tests for how L{InfiniteRedirection} attributes are initialized.
- """
- def test_noMessageValidStatus(self):
- """
- If no C{message} argument is passed to the L{InfiniteRedirection}
- constructor and the C{code} argument is a valid HTTP status code,
- C{code} is mapped to a descriptive string to which C{message} is
- assigned.
- """
- e = error.InfiniteRedirection(b"200", location=b"/foo")
- self.assertEqual(e.message, b"OK to /foo")
- def test_noMessageValidStatusNoLocation(self):
- """
- If no C{message} argument is passed to the L{InfiniteRedirection}
- constructor and C{location} is also empty and the C{code} argument is a
- valid HTTP status code, C{code} is mapped to a descriptive string to
- which C{message} is assigned without trying to include an empty
- location.
- """
- e = error.InfiniteRedirection(b"200")
- self.assertEqual(e.message, b"OK")
- def test_noMessageInvalidStatusLocationExists(self):
- """
- If no C{message} argument is passed to the L{InfiniteRedirection}
- constructor and C{code} isn't a valid HTTP status code, C{message} stays
- L{None}.
- """
- e = error.InfiniteRedirection(b"InvalidCode", location=b"/foo")
- self.assertEqual(e.message, None)
- def test_messageExistsLocationExists(self):
- """
- If a C{message} argument is passed to the L{InfiniteRedirection}
- constructor, the C{message} isn't affected by the value of C{status}.
- """
- e = error.InfiniteRedirection(b"200", b"My own message",
- location=b"/foo")
- self.assertEqual(e.message, b"My own message to /foo")
- def test_messageExistsNoLocation(self):
- """
- If a C{message} argument is passed to the L{InfiniteRedirection}
- constructor and no location is provided, C{message} doesn't try to
- include the empty location.
- """
- e = error.InfiniteRedirection(b"200", b"My own message")
- self.assertEqual(e.message, b"My own message")
- class RedirectWithNoLocationTests(unittest.TestCase):
- """
- L{RedirectWithNoLocation} is a subclass of L{Error} which sets
- a custom message in the constructor.
- """
- def test_validMessage(self):
- """
- When C{code}, C{message}, and C{uri} are passed to the
- L{RedirectWithNoLocation} constructor, the C{message} and C{uri}
- attributes are set, respectively.
- """
- e = error.RedirectWithNoLocation(b"302", b"REDIRECT",
- b"https://example.com")
- self.assertEqual(e.message, b"REDIRECT to https://example.com")
- self.assertEqual(e.uri, b"https://example.com")
- class MissingRenderMethodTests(unittest.TestCase):
- """
- Tests for how L{MissingRenderMethod} exceptions are initialized and
- displayed.
- """
- def test_constructor(self):
- """
- Given C{element} and C{renderName} arguments, the
- L{MissingRenderMethod} constructor assigns the values to the
- corresponding attributes.
- """
- elt = object()
- e = error.MissingRenderMethod(elt, 'renderThing')
- self.assertIs(e.element, elt)
- self.assertIs(e.renderName, 'renderThing')
- def test_repr(self):
- """
- A L{MissingRenderMethod} is represented using a custom string
- containing the element's representation and the method name.
- """
- elt = object()
- e = error.MissingRenderMethod(elt, 'renderThing')
- self.assertEqual(
- repr(e),
- ("'MissingRenderMethod': "
- "%r had no render method named 'renderThing'") % elt)
- class MissingTemplateLoaderTests(unittest.TestCase):
- """
- Tests for how L{MissingTemplateLoader} exceptions are initialized and
- displayed.
- """
- def test_constructor(self):
- """
- Given an C{element} argument, the L{MissingTemplateLoader} constructor
- assigns the value to the corresponding attribute.
- """
- elt = object()
- e = error.MissingTemplateLoader(elt)
- self.assertIs(e.element, elt)
- def test_repr(self):
- """
- A L{MissingTemplateLoader} is represented using a custom string
- containing the element's representation and the method name.
- """
- elt = object()
- e = error.MissingTemplateLoader(elt)
- self.assertEqual(
- repr(e),
- "'MissingTemplateLoader': %r had no loader" % elt)
- class FlattenerErrorTests(unittest.TestCase):
- """
- Tests for L{FlattenerError}.
- """
- def makeFlattenerError(self, roots=[]):
- try:
- raise RuntimeError("oh noes")
- except Exception as e:
- tb = traceback.extract_tb(sys.exc_info()[2])
- return error.FlattenerError(e, roots, tb)
- def fakeFormatRoot(self, obj):
- return 'R(%s)' % obj
- def test_constructor(self):
- """
- Given C{exception}, C{roots}, and C{traceback} arguments, the
- L{FlattenerError} constructor assigns the roots to the C{_roots}
- attribute.
- """
- e = self.makeFlattenerError(roots=['a', 'b'])
- self.assertEqual(e._roots, ['a', 'b'])
- def test_str(self):
- """
- The string form of a L{FlattenerError} is identical to its
- representation.
- """
- e = self.makeFlattenerError()
- self.assertEqual(str(e), repr(e))
- def test_reprWithRootsAndWithTraceback(self):
- """
- The representation of a L{FlattenerError} initialized with roots and a
- traceback contains a formatted representation of those roots (using
- C{_formatRoot}) and a formatted traceback.
- """
- e = self.makeFlattenerError(['a', 'b'])
- e._formatRoot = self.fakeFormatRoot
- self.assertTrue(
- re.match('Exception while flattening:\n'
- ' R\(a\)\n'
- ' R\(b\)\n'
- ' File "[^"]*", line [0-9]*, in makeFlattenerError\n'
- ' raise RuntimeError\("oh noes"\)\n'
- 'RuntimeError: oh noes\n$',
- repr(e), re.M | re.S),
- repr(e))
- def test_reprWithoutRootsAndWithTraceback(self):
- """
- The representation of a L{FlattenerError} initialized without roots but
- with a traceback contains a formatted traceback but no roots.
- """
- e = self.makeFlattenerError([])
- self.assertTrue(
- re.match('Exception while flattening:\n'
- ' File "[^"]*", line [0-9]*, in makeFlattenerError\n'
- ' raise RuntimeError\("oh noes"\)\n'
- 'RuntimeError: oh noes\n$',
- repr(e), re.M | re.S),
- repr(e))
- def test_reprWithoutRootsAndWithoutTraceback(self):
- """
- The representation of a L{FlattenerError} initialized without roots but
- with a traceback contains a formatted traceback but no roots.
- """
- e = error.FlattenerError(RuntimeError("oh noes"), [], None)
- self.assertTrue(
- re.match('Exception while flattening:\n'
- 'RuntimeError: oh noes\n$',
- repr(e), re.M | re.S),
- repr(e))
- def test_formatRootShortUnicodeString(self):
- """
- The C{_formatRoot} method formats a short unicode string using the
- built-in repr.
- """
- e = self.makeFlattenerError()
- self.assertEqual(e._formatRoot(nativeString('abcd')), repr('abcd'))
- def test_formatRootLongUnicodeString(self):
- """
- The C{_formatRoot} method formats a long unicode string using the
- built-in repr with an ellipsis.
- """
- e = self.makeFlattenerError()
- longString = nativeString('abcde-' * 20)
- self.assertEqual(e._formatRoot(longString),
- repr('abcde-abcde-abcde-ab<...>e-abcde-abcde-abcde-'))
- def test_formatRootShortByteString(self):
- """
- The C{_formatRoot} method formats a short byte string using the
- built-in repr.
- """
- e = self.makeFlattenerError()
- self.assertEqual(e._formatRoot(b'abcd'), repr(b'abcd'))
- def test_formatRootLongByteString(self):
- """
- The C{_formatRoot} method formats a long byte string using the
- built-in repr with an ellipsis.
- """
- e = self.makeFlattenerError()
- longString = b'abcde-' * 20
- self.assertEqual(e._formatRoot(longString),
- repr(b'abcde-abcde-abcde-ab<...>e-abcde-abcde-abcde-'))
- def test_formatRootTagNoFilename(self):
- """
- The C{_formatRoot} method formats a C{Tag} with no filename information
- as 'Tag <tagName>'.
- """
- e = self.makeFlattenerError()
- self.assertEqual(e._formatRoot(Tag('a-tag')), 'Tag <a-tag>')
- def test_formatRootTagWithFilename(self):
- """
- The C{_formatRoot} method formats a C{Tag} with filename information
- using the filename, line, column, and tag information
- """
- e = self.makeFlattenerError()
- t = Tag('a-tag', filename='tpl.py', lineNumber=10, columnNumber=20)
- self.assertEqual(e._formatRoot(t),
- 'File "tpl.py", line 10, column 20, in "a-tag"')
- def test_string(self):
- """
- If a L{FlattenerError} is created with a string root, up to around 40
- bytes from that string are included in the string representation of the
- exception.
- """
- self.assertEqual(
- str(error.FlattenerError(RuntimeError("reason"),
- ['abc123xyz'], [])),
- "Exception while flattening:\n"
- " 'abc123xyz'\n"
- "RuntimeError: reason\n")
- self.assertEqual(
- str(error.FlattenerError(
- RuntimeError("reason"), ['0123456789' * 10], [])),
- "Exception while flattening:\n"
- " '01234567890123456789"
- "<...>01234567890123456789'\n" # TODO: re-add 0
- "RuntimeError: reason\n")
- def test_unicode(self):
- """
- If a L{FlattenerError} is created with a unicode root, up to around 40
- characters from that string are included in the string representation
- of the exception.
- """
- # the response includes the output of repr(), which differs between
- # Python 2 and 3
- u = {'u': ''} if _PY3 else {'u': 'u'}
- self.assertEqual(
- str(error.FlattenerError(
- RuntimeError("reason"), [u'abc\N{SNOWMAN}xyz'], [])),
- "Exception while flattening:\n"
- " %(u)s'abc\\u2603xyz'\n" # Codepoint for SNOWMAN
- "RuntimeError: reason\n" % u)
- self.assertEqual(
- str(error.FlattenerError(
- RuntimeError("reason"), [u'01234567\N{SNOWMAN}9' * 10],
- [])),
- "Exception while flattening:\n"
- " %(u)s'01234567\\u2603901234567\\u26039"
- "<...>01234567\\u2603901234567"
- "\\u26039'\n"
- "RuntimeError: reason\n" % u)
- class UnsupportedMethodTests(unittest.SynchronousTestCase):
- """
- Tests for L{UnsupportedMethod}.
- """
- def test_str(self):
- """
- The C{__str__} for L{UnsupportedMethod} makes it clear that what it
- shows is a list of the supported methods, not the method that was
- unsupported.
- """
- b = "b" if _PY3 else ""
- e = error.UnsupportedMethod([b"HEAD", b"PATCH"])
- self.assertEqual(
- str(e), "Expected one of [{b}'HEAD', {b}'PATCH']".format(b=b),
- )
|