better_twill.py :  » Project-Management » Trac » Trac-0.11.7 » trac » tests » functional » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Project Management » Trac 
Trac » Trac 0.11.7 » trac » tests » functional » better_twill.py
#!/usr/bin/python
"""better_twill is a small wrapper around twill to set some sane defaults and
monkey-patch some better versions of some of twill's methods.
It also handles twill's absense.
"""

import os
from os.path import abspath,dirname,join
import sys
from pkg_resources import parse_version
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

# On OSX lxml needs to be imported before twill to avoid Resolver issues
# somehow caused by the mac specific 'ic' module
try:
    from lxml import etree
except ImportError:
    pass

try:
    import twill
except ImportError:
    twill = None

# When twill tries to connect to a site before the site is up, it raises an
# exception.  In 0.9b1, it's urlib2.URLError, but in -latest, it's
# _mechanize_dist._mechanize.BrowserStateError.
try:
    from _mechanize_dist._mechanize import BrowserStateError
except ImportError:
    from urllib2 import URLError


if twill:
    # We want Trac to generate valid html, and therefore want to test against
    # the html as generated by Trac.  "tidy" tries to clean up broken html, and
    # is responsible for one difficult to track down testcase failure (for
    # #5497).  Therefore we turn it off here.
    twill.commands.config('use_tidy', '0')

    # setup short names to reduce typing
    # This twill browser (and the tc commands that use it) are essentially
    # global, and not tied to our test fixture.
    tc = twill.commands
    b = twill.get_browser()

    # Setup XHTML validation for all retrieved pages
    try:
        from lxml import etree
    except ImportError:
        print "SKIP: validation of XHTML output in functional tests " \
              "(no lxml installed)"
        etree = None

    if etree and pv(etree.__version__) < pv('2.0.0'):
        # 2.0.7 and 2.1.x are known to work.
        print "SKIP: validation of XHTML output in functional tests " \
              "(lxml < 2.0, api incompatibility)"
        etree = None

    if etree:
        class _Resolver(etree.Resolver):
            base_dir = dirname(abspath(__file__))

            def resolve(self, system_url, public_id, context):
                return self.resolve_filename(join(self.base_dir,
                                                  system_url.split("/")[-1]),
                                             context)

        _parser = etree.XMLParser(dtd_validation=True)
        _parser.resolvers.add(_Resolver())
        etree.set_default_parser(_parser)

        def _format_error_log(data, log):
            msg = []
            for entry in log:
                context = data.splitlines()[max(0, entry.line - 5):
                                            entry.line + 6]
                msg.append("\n# %s\n# URL: %s\n# Line %d, column %d\n\n%s\n"
                    % (entry.message, entry.filename, 
                       entry.line, entry.column,
                       "\n".join([each.decode('utf-8') for each in context])))
            return "\n".join(msg).encode('ascii', 'xmlcharrefreplace')

        def _validate_xhtml(func_name, *args, **kwargs):
            page = b.get_html()
            if "xhtml1-strict.dtd" not in page:
                return
            etree.clear_error_log()
            try:
                doc = etree.parse(StringIO(page), base_url=b.get_url())
            except etree.XMLSyntaxError, e:
                raise twill.errors.TwillAssertionError(
                    _format_error_log(page, e.error_log))

        b._post_load_hooks.append(_validate_xhtml)

    # When we can't find something we expected, or find something we didn't
    # expect, it helps the debugging effort to have a copy of the html to
    # analyze.
    def twill_write_html():
        """Write the current html to a file.  Name the file based on the
        current testcase.
        """
        frame = sys._getframe()
        while frame:
            if frame.f_code.co_name in ('runTest', 'setUp', 'tearDown'):
                testcase = frame.f_locals['self']
                testname = testcase.__class__.__name__
                tracdir = testcase._testenv.tracdir
                break
            frame = frame.f_back
        else:
            # We didn't find a testcase in the stack, so we have no clue what's
            # going on.
            raise Exception("No testcase was found on the stack.  This was "
                "really not expected, and I don't know how to handle it.")

        filename = os.path.join(tracdir, 'log', "%s.html" % testname)
        html_file = open(filename, 'w')
        html_file.write(b.get_html())
        html_file.close()

        return filename

    # Twill isn't as helpful with errors as I'd like it to be, so we replace
    # the formvalue function.  This would be better done as a patch to Twill.
    def better_formvalue(form, field, value, fv=tc.formvalue):
        try:
            fv(form, field, value)
        except (twill.errors.TwillAssertionError,
                twill.utils.ClientForm.ItemNotFoundError), e:
            filename = twill_write_html()
            args = e.args + (filename,)
            raise twill.errors.TwillAssertionError(*args)
    tc.formvalue = better_formvalue
    tc.fv = better_formvalue

    # Twill's formfile function leaves a filehandle open which prevents the
    # file from being deleted on Windows.  Since we would just assume use a
    # StringIO object in the first place, allow the file-like object to be
    # provided directly.
    def better_formfile(formname, fieldname, filename, content_type=None,
                        fp=None):
        if not fp:
            filename = filename.replace('/', os.path.sep)
            temp_fp = open(filename, 'rb')
            data = temp_fp.read()
            temp_fp.close()
            fp = StringIO(data)

        form = b.get_form(formname)
        control = b.get_form_field(form, fieldname)

        if not control.is_of_kind('file'):
            raise twill.errors.TwillException('ERROR: field is not a file '
                                              'upload field!')

        b.clicked(form, control)
        control.add_file(fp, content_type, filename)
    tc.formfile = better_formfile

    # Twill's tc.find() does not provide any guidance on what we got instead of
    # what was expected.
    def better_find(what, flags='', tcfind=tc.find):
        try:
            tcfind(what, flags)
        except twill.errors.TwillAssertionError, e:
            filename = twill_write_html()
            args = e.args + (filename,)
            raise twill.errors.TwillAssertionError(*args)
    tc.find = better_find
    def better_notfind(what, flags='', tcnotfind=tc.notfind):
        try:
            tcnotfind(what, flags)
        except twill.errors.TwillAssertionError, e:
            filename = twill_write_html()
            args = e.args + (filename,)
            raise twill.errors.TwillAssertionError(*args)
    tc.notfind = better_notfind
else:
    b = tc = None
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.