zope.testing-4.1.2/tox.ini0000644000000000000000000000046212110747242013612 0ustar 00000000000000[tox] envlist = py26,py27,py32,py33 [testenv] commands = python setup.py test -q # without explicit deps, setup.py test will download a bunch of eggs into $PWD # (and it seems I can't use zope.dottedname[testing] here, so forget DRY) deps = zope.testing zope.exceptions zope.interface zope.testing-4.1.2/CHANGES.rst0000644000000000000000000002672312110747242014111 0ustar 00000000000000zope.testing Changelog ********************** 4.1.2 (2013-02-19) ================== - Adjusted Trove classifiers to reflect the currently supported Python versions. Officially drop Python 2.4 and 2.5. Added Python 3.3. - LP: #1055720: Fix failing test on Python 3.3 due to changed exception messaging. 4.1.1 (2012-02-01) ================== - Fixed: Windows test failure. 4.1.0 (2012-01-29) ================== - Added context-manager support to ``zope.testing.setupstack`` - Made ``zope.testing.setupstack`` usable with all tests, not just doctests and added ``zope.testing.setupstack.globs``, which makes it easier to write test setup code that workes with doctests and other kinds of tests. - Added the ``wait`` module, which makes it easier to deal with non-deterministic timing issues. - Renamed ``zope.testing.renormalizing.RENormalizing`` to ``zope.testing.renormalizing.OutputChecker``. The old name is an alias. - Updated tests to run with Python 3. - More clearly labeled which features were supported by Python 3. - Reorganized documentation. 4.0.0 (2011-11-09) ================== - Removes the deprecated zope.testing.doctest. - Adds Python 3 support. - Fixed test which fails if there is a file named `Data.fs` in the current working directory. 3.10.2 (2010-11-30) =================== - Fix test of broken symlink handling to not break on Windows. 3.10.1 (2010-11-29) =================== - Fix removal of broken symlinks on Unix. 3.10.0 (2010-07-21) =================== - Removed zope.testing.testrunner, which now is moved to zope.testrunner. - Update fix for LP #221151 to a spelling compatible with Python 2.4. 3.9.5 (2010-05-19) ================== - LP #579019: When layers were run in parallel, their tearDown was not called. Additionally, the first layer which was run in the main thread did not have it's tearDown called either. - Deprecated zope.testing.testrunner and zope.testing.exceptions. They have been moved to a separate zope.testrunner module, and will be removed from zope.testing in 4.0.0, together with zope.testing.doctest. 3.9.4 (2010-04-13) ================== - LP #560259: Fix subunit output formatter to handle layer setup errors. - LP #399394: Added a ``--stop-on-error`` / ``--stop`` / ``-x`` option to the testrunner. - LP #498162: Added a ``--pdb`` alias for the existing ``--post-mortem`` / ``-D`` option to the testrunner. - LP #547023: Added a ``--version`` option to the testrunner. - Added tests for LP #144569 and #69988. https://bugs.launchpad.net/bugs/69988 https://bugs.launchpad.net/zope3/+bug/144569 3.9.3 (2010-03-26) ================== - zope.testing.renormalizer no longer imports zope.testing.doctest, which caused deprecation warnings. - Fix testrunner-layers-ntd.txt to suppress output to sys.stderr. - Suppress zope.testing.doctest deprecation warning when running zope.testing's own test suite. 3.9.2 (2010-03-15) ================== - Fixed broken ``from zope.testing.doctest import *`` 3.9.1 (2010-03-15) ================== - No changes; reuploaded to fix broken 3.9.0 release on PyPI. 3.9.0 (2010-03-12) ================== - Modified the testrunner to use the standard Python doctest module instead of the deprecated zope.testing.doctest. - Fix testrunner-leaks.txt to use the run_internal helper, so that sys.exit() isn't triggered during the test run. - Added support for conditionally using a subunit-based output formatter upon request if subunit and testtools are available. Patch contributed by Jonathan Lange. 3.8.7 (2010-01-26) ================== - Downgraded the zope.testing.doctest deprecation warning into a PendingDeprecationWarning. 3.8.6 (2009-12-23) ================== - Added MANIFEST.in and reuploaded to fix broken 3.8.5 release on PyPI. 3.8.5 (2009-12-23) ================== - Added DocFileSuite, DocTestSuite, debug_src and debug back BBB imports back into zope.testing.doctestunit; apparently many packages still import them from there! - Made zope.testing.doctest and zope.testing.doctestunit emit deprecation warnings: use the stdlib doctest instead. 3.8.4 (2009-12-18) ================== - Fixed missing imports and undefined variables reported by pyflakes, adding tests to exercise the blind spots. - Cleaned up unused imports reported by pyflakes. - Added two new options to generate randomly ordered list of tests and to select a specific order of tests. - RENormalizing checkers can be combined via ``+`` now: ``checker1 + checker2`` creates a checker with the transformations of both checkers. - Test fixes for Python 2.7. 3.8.3 (2009-09-21) ================== - Avoid a split() call or we get test failures when running from a directory with spaces in it. - Fix testrunner behavior on Windows for -j2 (or greater) combined with -v (or greater). 3.8.2 (2009-09-15) ================== - Removing hotshot profiler when using Python 2.6. That makes zope.testing compatible with Python 2.6 3.8.1 (2009-08-12) ================== - Avoid hardcoding sys.argv[0] as script; allow, for instance, Zope 2's `bin/instance test` (LP#407916). - Produce a clear error message when a subprocess doesn't follow the zope.testing.testrunner protocol (LP#407916). - Do not unnecessarily squelch verbose output in a subprocess when there are not multiple subprocesses. - Do not unnecessarily batch subprocess output, which can stymie automated and human processes for identifying hung tests. - Include incremental output when there are multiple subprocesses and a verbosity of -vv or greater is requested. This again is not batched, supporting automated processes and humans looking for hung tests. 3.8.0 (2009-07-24) ================== - Testrunner automatically picks up descendants of unittest.TestCase in test modules, so you don't have to provide a test_suite() anymore. 3.7.7 (2009-07-15) ================== - Clean up support for displaying tracebacks with supplements by turning it into an always-enabled feature and making the dependency on zope.exceptions explicit. - Fix #251759: Test runner descended into directories that aren't Python packages. - Code cleanups. 3.7.6 (2009-07-02) ================== - Add zope-testrunner console_scripts entry point. This exposes a zope-testrunner binary with default installs allowing the testrunner to be run from the command line. 3.7.5 (2009-06-08) ================== - Fix bug when running subprocesses on Windows. - The option REPORT_ONLY_FIRST_FAILURE (command line option "-1") is now respected even when a doctest declares its own REPORTING_FLAGS, such as REPORT_NDIFF. - Fixed bug that broke readline with pdb when using doctest (see http://bugs.python.org/issue5727). - Made tests pass on Windows and Linux at the same time. 3.7.4 (2009-05-01) ================== - Filenames of doctest examples now contain the line number and not only the example number. So a stack trace in pdb tells the exact line number of the current example. This fixes https://bugs.launchpad.net/bugs/339813 - Colorization of doctest output correctly handles blank lines. 3.7.3 (2009-04-22) ================== - Better deal with rogue threads by always exiting with status so even spinning daemon threads won't block the runner from exiting. This deprecated the ``--with-exit-status`` option. 3.7.2 (2009-04-13) ================== - fix test failure on Python 2.4 because of slight difference in the way coverage is reported (__init__ files with only a single comment line are now not reported) - fixed bug that caused the test runner to hang when running subprocesses (as a result Python 2.3 is no longer supported). - there is apparently a bug in Python 2.6 (related to http://bugs.python.org/issue1303673) that causes the profile tests to fail. - added explanitory notes to buildout.cfg about how to run the tests with multiple versions of Python 3.7.1 (2008-10-17) ================== - The setupstack temporary-directory support now properly handles read-only files by making them writable before removing them. 3.7.0 (2008-09-22) ================== - Added an alterate setuptools / distutils commands for running all tests using our testrunner. See 'zope.testing.testrunner.eggsupport:ftest'. - Added a setuptools-compatible test loader which skips tests with layers: the testrunner used by 'setup.py test' doesn't know about them, and those tests then fail. See 'zope.testing.testrunner.eggsupport:SkipLayers'. - Added support for Jython, when a garbage collector call is sent. - Added support to bootstrap on Jython. - Fixed NameError in StartUpFailure. - Open doctest files in universal mode, so that packages released on Windows can be tested on Linux, for example. 3.6.0 (2008/07/10) ================== - Added -j option to parallel tests run in subprocesses. - RENormalizer accepts plain Python callables. - Added --slow-test option. - Added --no-progress and --auto-progress options. - Complete refactoring of the test runner into multiple code files and a more modular (pipeline-like) architecture. - Unified unit tests with the layer support by introducing a real unit test layer. - Added a doctest for ``zope.testing.module``. There were several bugs that were fixed: * ``README.txt`` was a really bad default argument for the module name, as it is not a proper dotted name. The code would immediately fail as it would look for the ``txt`` module in the ``README`` package. The default is now ``__main__``. * The tearDown function did not clean up the ``__name__`` entry in the global dictionary. - Fix a bug that caused a SubprocessError to be generated if a subprocess sent any output to stderr. - Fix a bug that caused the unit tests to be skipped if run in a subprocess. 3.5.1 (2007/08/14) ================== Bugs Fixed: ----------- - Post-mortem debugging wasn't invoked for layer-setup failures. 3.5.0 (2007/07/19) ================== New Features ------------ - The test runner now works on Python 2.5. - Added support for cProfile. - Added output colorizing (-c option). - Added --hide-secondary-failures and --show-secondary-failures options (https://bugs.launchpad.net/zope3/+bug/115454). Bugs Fixed: ----------- - Fix some problems with Unicode in doctests. - Fix "Error reading from subprocess" errors on Unix-like systems. 3.4 (2007/03/29) ================ New Features ------------ - Added exit-with-status support (supports use with buildbot and zc.recipe.testing) - Added a small framework for automating set up and tear down of doctest tests. See setupstack.txt. Bugs Fixed: ----------- - Fix testrunner-wo-source.txt and testrunner-errors.txt to run with a read-only source tree. 3.0 (2006/09/20) ================ - Updated the doctest copy with text-file encoding support. - Added logging-level support to loggingsuppport module. - At verbosity-level 1, dots are not output continuously, without any line breaks. - Improved output when the inability to tear down a layer causes tests to be run in a subprocess. - Made zope.exception required only if the zope_tracebacks extra is requested. 2.x.y (???) =========== - Fix the test coverage. If a module, for example `interfaces`, was in an ignored directory/package, then if a module of the same name existed in a covered directory/package, then it was also ignored there, because the ignore cache stored the result by module name and not the filename of the module. 2.0 (2006/01/05) ================ - Corresponds to the version of the zope.testing package shipped as part of the Zope 3.2.0 release. zope.testing-4.1.2/setup.cfg0000644000000000000000000000007312110747252014117 0ustar 00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zope.testing-4.1.2/COPYRIGHT.txt0000644000000000000000000000004012110747242014400 0ustar 00000000000000Zope Foundation and Contributorszope.testing-4.1.2/bootstrap.py0000644000000000000000000002352212110747242014670 0ustar 00000000000000############################################################################## # # Copyright (c) 2006 Zope Foundation 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. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. """ import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess from optparse import OptionParser if sys.platform == 'win32': def quote(c): if ' ' in c: return '"%s"' % c # work around spawn lamosity on windows else: return c else: quote = str # See zc.buildout.easy_install._has_broken_dash_S for motivation and comments. stdout, stderr = subprocess.Popen( [sys.executable, '-Sc', 'try:\n' ' import ConfigParser\n' 'except ImportError:\n' ' print 1\n' 'else:\n' ' print 0\n'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() has_broken_dash_S = bool(int(stdout.strip())) # In order to be more robust in the face of system Pythons, we want to # run without site-packages loaded. This is somewhat tricky, in # particular because Python 2.6's distutils imports site, so starting # with the -S flag is not sufficient. However, we'll start with that: if not has_broken_dash_S and 'site' in sys.modules: # We will restart with python -S. args = sys.argv[:] args[0:0] = [sys.executable, '-S'] args = map(quote, args) os.execv(sys.executable, args) # Now we are running with -S. We'll get the clean sys.path, import site # because distutils will do it later, and then reset the path and clean # out any namespace packages from site-packages that might have been # loaded by .pth files. clean_path = sys.path[:] import site sys.path[:] = clean_path for k, v in sys.modules.items(): if k in ('setuptools', 'pkg_resources') or ( hasattr(v, '__path__') and len(v.__path__)==1 and not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))): # This is a namespace package. Remove it. sys.modules.pop(k) is_jython = sys.platform.startswith('java') setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py' distribute_source = 'http://python-distribute.org/distribute_setup.py' # parsing arguments def normalize_to_url(option, opt_str, value, parser): if value: if '://' not in value: # It doesn't smell like a URL. value = 'file://%s' % ( urllib.pathname2url( os.path.abspath(os.path.expanduser(value))),) if opt_str == '--download-base' and not value.endswith('/'): # Download base needs a trailing slash to make the world happy. value += '/' else: value = None name = opt_str[2:].replace('-', '_') setattr(parser.values, name, value) usage = '''\ [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] Bootstraps a buildout-based project. Simply run this script in a directory containing a buildout.cfg, using the Python that you want bin/buildout to use. Note that by using --setup-source and --download-base to point to local resources, you can keep this script from going over the network. ''' parser = OptionParser(usage=usage) parser.add_option("-v", "--version", dest="version", help="use a specific zc.buildout version") parser.add_option("-d", "--distribute", action="store_true", dest="use_distribute", default=False, help="Use Distribute rather than Setuptools.") parser.add_option("--setup-source", action="callback", dest="setup_source", callback=normalize_to_url, nargs=1, type="string", help=("Specify a URL or file location for the setup file. " "If you use Setuptools, this will default to " + setuptools_source + "; if you use Distribute, this " "will default to " + distribute_source +".")) parser.add_option("--download-base", action="callback", dest="download_base", callback=normalize_to_url, nargs=1, type="string", help=("Specify a URL or directory for downloading " "zc.buildout and either Setuptools or Distribute. " "Defaults to PyPI.")) parser.add_option("--eggs", help=("Specify a directory for storing eggs. Defaults to " "a temporary directory that is deleted when the " "bootstrap script completes.")) parser.add_option("-t", "--accept-buildout-test-releases", dest='accept_buildout_test_releases', action="store_true", default=False, help=("Normally, if you do not specify a --version, the " "bootstrap script and buildout gets the newest " "*final* versions of zc.buildout and its recipes and " "extensions for you. If you use this flag, " "bootstrap and buildout will get the newest releases " "even if they are alphas or betas.")) parser.add_option("-c", None, action="store", dest="config_file", help=("Specify the path to the buildout configuration " "file to be used.")) options, args = parser.parse_args() # if -c was provided, we push it back into args for buildout's main function if options.config_file is not None: args += ['-c', options.config_file] if options.eggs: eggs_dir = os.path.abspath(os.path.expanduser(options.eggs)) else: eggs_dir = tempfile.mkdtemp() if options.setup_source is None: if options.use_distribute: options.setup_source = distribute_source else: options.setup_source = setuptools_source if options.accept_buildout_test_releases: args.append('buildout:accept-buildout-test-releases=true') args.append('bootstrap') try: import pkg_resources import setuptools # A flag. Sometimes pkg_resources is installed alone. if not hasattr(pkg_resources, '_distribute'): raise ImportError except ImportError: ez_code = urllib2.urlopen( options.setup_source).read().replace('\r\n', '\n') ez = {} exec ez_code in ez setup_args = dict(to_dir=eggs_dir, download_delay=0) if options.download_base: setup_args['download_base'] = options.download_base if options.use_distribute: setup_args['no_fake'] = True ez['use_setuptools'](**setup_args) if 'pkg_resources' in sys.modules: reload(sys.modules['pkg_resources']) import pkg_resources # This does not (always?) update the default working set. We will # do it. for path in sys.path: if path not in pkg_resources.working_set.entries: pkg_resources.working_set.add_entry(path) cmd = [quote(sys.executable), '-c', quote('from setuptools.command.easy_install import main; main()'), '-mqNxd', quote(eggs_dir)] if not has_broken_dash_S: cmd.insert(1, '-S') find_links = options.download_base if not find_links: find_links = os.environ.get('bootstrap-testing-find-links') if find_links: cmd.extend(['-f', quote(find_links)]) if options.use_distribute: setup_requirement = 'distribute' else: setup_requirement = 'setuptools' ws = pkg_resources.working_set setup_requirement_path = ws.find( pkg_resources.Requirement.parse(setup_requirement)).location env = dict( os.environ, PYTHONPATH=setup_requirement_path) requirement = 'zc.buildout' version = options.version if version is None and not options.accept_buildout_test_releases: # Figure out the most recent final version of zc.buildout. import setuptools.package_index _final_parts = '*final-', '*final' def _final_version(parsed_version): for part in parsed_version: if (part[:1] == '*') and (part not in _final_parts): return False return True index = setuptools.package_index.PackageIndex( search_path=[setup_requirement_path]) if find_links: index.add_find_links((find_links,)) req = pkg_resources.Requirement.parse(requirement) if index.obtain(req) is not None: best = [] bestv = None for dist in index[req.project_name]: distv = dist.parsed_version if _final_version(distv): if bestv is None or distv > bestv: best = [dist] bestv = distv elif distv == bestv: best.append(dist) if best: best.sort() version = best[-1].version if version: requirement = '=='.join((requirement, version)) cmd.append(requirement) if is_jython: import subprocess exitcode = subprocess.Popen(cmd, env=env).wait() else: # Windows prefers this, apparently; otherwise we would prefer subprocess exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) if exitcode != 0: sys.stdout.flush() sys.stderr.flush() print ("An error occurred when trying to install zc.buildout. " "Look above this message for any errors that " "were output by easy_install.") sys.exit(exitcode) ws.add_entry(eggs_dir) ws.require(requirement) import zc.buildout.buildout zc.buildout.buildout.main(args) if not options.eggs: # clean up temporary egg directory shutil.rmtree(eggs_dir) zope.testing-4.1.2/buildout.cfg0000644000000000000000000000015712110747242014610 0ustar 00000000000000[buildout] develop = . parts = test unzip = true [test] recipe = zc.recipe.testrunner eggs = zope.testing zope.testing-4.1.2/setup.py0000644000000000000000000000652212110747242014014 0ustar 00000000000000############################################################################## # # Copyright (c) 2004 Zope Foundation 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. # ############################################################################## # This package is developed by the Zope Toolkit project, documented here: # http://docs.zope.org/zopetoolkit # When developing and releasing this package, please follow the documented # Zope Toolkit policies as described by this documentation. ############################################################################## """Setup for zope.testing package """ import os from setuptools import setup import sys if sys.version > '3': extras = dict( use_2to3 = True, convert_2to3_doctests = ['src/zope/testing/doctest.txt', 'src/zope/testing/formparser.txt', 'src/zope/testing/module.txt', 'src/zope/testing/setupstack.txt', ], ) else: extras = {} chapters = '\n'.join([ open(os.path.join('src', 'zope', 'testing', name)).read() for name in ( 'formparser.txt', 'loggingsupport.txt', 'renormalizing.txt', 'setupstack.txt', 'wait.txt', )]) long_description=( open('README.rst').read() + '\n' + 'Detailed Documentation\n' '**********************\n' + '\n' + chapters + '\n' + open('CHANGES.rst').read() ) setup( name='zope.testing', version='4.1.2', url='http://pypi.python.org/pypi/zope.testing', license='ZPL 2.1', description='Zope testing helpers', long_description=long_description, author='Zope Foundation and Contributors', author_email='zope-dev@zope.org', classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Zope Public License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", 'Programming Language :: Python :: Implementation :: CPython', "Framework :: Zope3", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Testing", ], packages=["zope", "zope.testing", "zope.testing.doctest", "zope.testing.renormalizing"], package_dir = {'': 'src'}, namespace_packages=['zope',], install_requires = ['setuptools', 'zope.exceptions', 'zope.interface'], include_package_data = True, zip_safe = False, test_suite = 'zope.testing.tests.test_suite', **extras ) zope.testing-4.1.2/MANIFEST.in0000644000000000000000000000033412110747242014033 0ustar 00000000000000include *.rst include *.txt include bootstrap.py include buildout.cfg include tox.ini recursive-include docs * recursive-include src * global-exclude *.dll global-exclude *.pyc global-exclude *.pyo global-exclude *.so zope.testing-4.1.2/README.rst0000644000000000000000000000303212110747242013762 0ustar 00000000000000************ zope.testing ************ .. contents:: This package provides a number of testing frameworks. cleanup Provides a mixin class for cleaning up after tests that make global changes. formparser An HTML parser that extracts form information. **Python 2 only** This is intended to support functional tests that need to extract information from HTML forms returned by the publisher. See formparser.txt. loggingsupport Support for testing logging code If you want to test that your code generates proper log output, you can create and install a handler that collects output. loghandler Logging handler for tests that check logging output. module Lets a doctest pretend to be a Python module. See module.txt. renormalizing Regular expression pattern normalizing output checker. Useful for doctests. server Provides a simple HTTP server compatible with the zope.app.testing functional testing API. Lets you interactively play with the system under test. Helpful in debugging functional doctest failures. **Python 2 only** setupstack A simple framework for automating doctest set-up and tear-down. See setupstack.txt. wait A small utility for dealing with timing non-determinism See wait.txt. Getting started *************** zope.testing uses buildout. To start, run ``python bootstrap.py``. It will create a number of directories and the ``bin/buildout`` script. Next, run ``bin/buildout``. It will create a test script for you. Now, run ``bin/test`` to run the zope.testing test suite. zope.testing-4.1.2/PKG-INFO0000644000000000000000000013212612110747252013400 0ustar 00000000000000Metadata-Version: 1.1 Name: zope.testing Version: 4.1.2 Summary: Zope testing helpers Home-page: http://pypi.python.org/pypi/zope.testing Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: ************ zope.testing ************ .. contents:: This package provides a number of testing frameworks. cleanup Provides a mixin class for cleaning up after tests that make global changes. formparser An HTML parser that extracts form information. **Python 2 only** This is intended to support functional tests that need to extract information from HTML forms returned by the publisher. See formparser.txt. loggingsupport Support for testing logging code If you want to test that your code generates proper log output, you can create and install a handler that collects output. loghandler Logging handler for tests that check logging output. module Lets a doctest pretend to be a Python module. See module.txt. renormalizing Regular expression pattern normalizing output checker. Useful for doctests. server Provides a simple HTTP server compatible with the zope.app.testing functional testing API. Lets you interactively play with the system under test. Helpful in debugging functional doctest failures. **Python 2 only** setupstack A simple framework for automating doctest set-up and tear-down. See setupstack.txt. wait A small utility for dealing with timing non-determinism See wait.txt. Getting started *************** zope.testing uses buildout. To start, run ``python bootstrap.py``. It will create a number of directories and the ``bin/buildout`` script. Next, run ``bin/buildout``. It will create a test script for you. Now, run ``bin/test`` to run the zope.testing test suite. Detailed Documentation ********************** Parsing HTML Forms ================== Sometimes in functional tests, information from a generated form must be extracted in order to re-submit it as part of a subsequent request. The `zope.testing.formparser` module can be used for this purpose. NOTE formparser doesn't support Python 3. The scanner is implemented using the `FormParser` class. The constructor arguments are the page data containing the form and (optionally) the URL from which the page was retrieved: >>> import zope.testing.formparser >>> page_text = '''\ ... ...
... ... ... ... ...
... ... Just for fun, a second form, after specifying a base: ... ...
... ... ... ... ...
... ... ''' >>> parser = zope.testing.formparser.FormParser(page_text) >>> forms = parser.parse() >>> len(forms) 2 >>> forms.form1 is forms[0] True >>> forms.form1 is forms[1] False More often, the `parse()` convenience function is all that's needed: >>> forms = zope.testing.formparser.parse( ... page_text, "http://cgi.example.com/somewhere/form.html") >>> len(forms) 2 >>> forms.form1 is forms[0] True >>> forms.form1 is forms[1] False Once we have the form we're interested in, we can check form attributes and individual field values: >>> form = forms.form1 >>> form.enctype 'application/x-www-form-urlencoded' >>> form.method 'post' >>> keys = form.keys() >>> keys.sort() >>> keys ['do-it-now', 'f1', 'not-really', 'pick-two'] >>> not_really = form["not-really"] >>> not_really.type 'image' >>> not_really.value "Don't." >>> not_really.readonly False >>> not_really.disabled False Note that relative URLs are converted to absolute URLs based on the ```` element (if present) or using the base passed in to the constructor. >>> form.action 'http://cgi.example.com/cgi-bin/foobar.py' >>> not_really.src 'http://cgi.example.com/somewhere/dont.png' >>> forms[1].action 'http://www.example.com/base/sproing/sprung.html' >>> forms[1]["action"].src 'http://www.example.com/base/else.png' Fields which are repeated are reported as lists of objects that represent each instance of the field:: >>> field = forms[1]["multi"] >>> isinstance(field, list) True >>> [o.value for o in field] ['', ''] >>> [o.size for o in field] [2, 3] The `` ... ... ... ... ... ... ''' >>> parser = zope.testing.formparser.FormParser(page_text) >>> forms = parser.parse() >>> len(forms) 2 >>> forms.form1 is forms[0] True >>> forms.form1 is forms[1] False More often, the `parse()` convenience function is all that's needed: >>> forms = zope.testing.formparser.parse( ... page_text, "http://cgi.example.com/somewhere/form.html") >>> len(forms) 2 >>> forms.form1 is forms[0] True >>> forms.form1 is forms[1] False Once we have the form we're interested in, we can check form attributes and individual field values: >>> form = forms.form1 >>> form.enctype 'application/x-www-form-urlencoded' >>> form.method 'post' >>> keys = form.keys() >>> keys.sort() >>> keys ['do-it-now', 'f1', 'not-really', 'pick-two'] >>> not_really = form["not-really"] >>> not_really.type 'image' >>> not_really.value "Don't." >>> not_really.readonly False >>> not_really.disabled False Note that relative URLs are converted to absolute URLs based on the ```` element (if present) or using the base passed in to the constructor. >>> form.action 'http://cgi.example.com/cgi-bin/foobar.py' >>> not_really.src 'http://cgi.example.com/somewhere/dont.png' >>> forms[1].action 'http://www.example.com/base/sproing/sprung.html' >>> forms[1]["action"].src 'http://www.example.com/base/else.png' Fields which are repeated are reported as lists of objects that represent each instance of the field:: >>> field = forms[1]["multi"] >>> isinstance(field, list) True >>> [o.value for o in field] ['', ''] >>> [o.size for o in field] [2, 3] The `` is seen. elif tag == "base": href = d.get("href", "").strip() if href and self.base: href = urlparse.urljoin(self.base, href) self.base = href elif tag == "select": disabled = "disabled" in d multiple = "multiple" in d size = intattr(d, "size") self.select = Select(name, id, disabled, multiple, size) self._add_field(self.select) elif tag == "option": disabled = "disabled" in d selected = "selected" in d value = d.get("value") label = d.get("label") option = Option(id, value, selected, label, disabled) self.select.options.append(option) # Helpers: def _add_field(self, field): if field.name in self.current: ob = self.current[field.name] if isinstance(ob, list): ob.append(field) else: self.current[field.name] = [ob, field] else: self.current[field.name] = field def kwattr(d, name, default=None): """Return attribute, converted to lowercase.""" v = d.get(name, default) if v != default and v is not None: v = v.strip().lower() v = v or default return v def intattr(d, name): """Return attribute as an integer, or None.""" if name in d: v = d[name].strip() return int(v) else: return None class FormCollection(list): """Collection of all forms from a page.""" def __getattr__(self, name): for form in self: if form.name == name: return form raise AttributeError(name) class Form(dict): """A specific form within a page.""" # This object should provide some method to prepare a dictionary # that can be passed directly as the value of the `form` argument # to the `http()` function of the Zope functional test. # # This is probably a low priority given the availability of the # `zope.testbrowser` package. def __init__(self, name, id, method, action, enctype): super(Form, self).__init__() self.name = name self.id = id self.method = method self.action = action self.enctype = enctype class Input(object): """Input element.""" rows = None cols = None def __init__(self, name, id, type, value, checked, disabled, readonly, src, size, maxlength): super(Input, self).__init__() self.name = name self.id = id self.type = type self.value = value self.checked = checked self.disabled = disabled self.readonly = readonly self.src = src self.size = size self.maxlength = maxlength class Select(Input): """Select element.""" def __init__(self, name, id, disabled, multiple, size): super(Select, self).__init__(name, id, "select", None, None, disabled, None, None, size, None) self.options = [] self.multiple = multiple if multiple: self.value = [] class Option(object): """Individual value representation for a select element.""" def __init__(self, id, value, selected, label, disabled): super(Option, self).__init__() self.id = id self.value = value self.selected = selected self.label = label self.disabled = disabled zope.testing-4.1.2/src/zope/testing/setupstack.py0000644000000000000000000000353612110747242020265 0ustar 00000000000000############################################################################## # # Copyright (c) 2005 Zope Foundation 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. # ############################################################################## """Stack-based test doctest setUp and tearDown See setupstack.txt """ import os, stat, tempfile key = '__' + __name__ def globs(test): try: return test.globs except AttributeError: return test.__dict__ def register(test, function, *args, **kw): tglobs = globs(test) stack = tglobs.get(key) if stack is None: stack = tglobs[key] = [] stack.append((function, args, kw)) def tearDown(test): tglobs = globs(test) stack = tglobs.get(key) while stack: f, p, k = stack.pop() f(*p, **k) def setUpDirectory(test): tmp = tempfile.mkdtemp() register(test, rmtree, tmp) here = os.getcwd() register(test, os.chdir, here) os.chdir(tmp) def rmtree(path): for path, dirs, files in os.walk(path, False): for fname in files: fname = os.path.join(path, fname) if not os.path.islink(fname): os.chmod(fname, stat.S_IWUSR) os.remove(fname) for dname in dirs: dname = os.path.join(path, dname) os.rmdir(dname) os.rmdir(path) def context_manager(test, manager): result = manager.__enter__() register(test, manager.__exit__, None, None, None) return result zope.testing-4.1.2/src/zope/testing/renormalizing.txt0000644000000000000000000001575712110747242021156 0ustar 00000000000000Regular expression pattern normalizing output checker ===================================================== The pattern-normalizing output checker extends the default output checker with an option to normalize expected and actual output. You specify a sequence of patterns and replacements. The replacements are applied to the expected and actual outputs before calling the default outputs checker. Let's look at an example. In this example, we have some times and addresses: >>> want = '''\ ... ... completed in 1.234 seconds. ... ... ... completed in 123.234 seconds. ... ... ... completed in .234 seconds. ... ... ... completed in 1.234 seconds. ... ... ''' >>> got = '''\ ... ... completed in 1.235 seconds. ... ... ... completed in 123.233 seconds. ... ... ... completed in .231 seconds. ... ... ... completed in 1.23 seconds. ... ... ''' We may wish to consider these two strings to match, even though they differ in actual addresses and times. The default output checker will consider them different: >>> import doctest >>> doctest.OutputChecker().check_output(want, got, 0) False We'll use the zope.testing.renormalizing.OutputChecker to normalize both the wanted and gotten strings to ignore differences in times and addresses: >>> import re >>> from zope.testing.renormalizing import OutputChecker >>> checker = OutputChecker([ ... (re.compile('[0-9]*[.][0-9]* seconds'), ' seconds'), ... (re.compile('at 0x[0-9a-f]+'), 'at '), ... ]) >>> checker.check_output(want, got, 0) True Usual OutputChecker options work as expected: >>> want_ellided = '''\ ... ... completed in 1.234 seconds. ... ... ... ... completed in 1.234 seconds. ... ... ''' >>> checker.check_output(want_ellided, got, 0) False >>> checker.check_output(want_ellided, got, doctest.ELLIPSIS) True When we get differencs, we output them with normalized text: >>> source = '''\ ... >>> do_something() ... ... completed in 1.234 seconds. ... ... ... ... completed in 1.234 seconds. ... ... ''' >>> example = doctest.Example(source, want_ellided) >>> print_(checker.output_difference(example, got, 0)) Expected: > completed in seconds. ... > completed in seconds. Got: > completed in seconds. > completed in seconds. > completed in seconds. > completed in seconds. >>> print_(checker.output_difference(example, got, ... doctest.REPORT_NDIFF)) Differences (ndiff with -expected +actual): - > - completed in seconds. - ... > completed in seconds. + > + completed in seconds. + + > + completed in seconds. + + > + completed in seconds. + If the wanted text is empty, however, we don't transform the actual output. This is usful when writing tests. We leave the expected output empty, run the test, and use the actual output as expected, after reviewing it. >>> source = '''\ ... >>> do_something() ... ''' >>> example = doctest.Example(source, '\n') >>> print_(checker.output_difference(example, got, 0)) Expected: Got: completed in 1.235 seconds. completed in 123.233 seconds. completed in .231 seconds. completed in 1.23 seconds. If regular expressions aren't expressive enough, you can use arbitrary Python callables to transform the text. For example, suppose you want to ignore case during comparison: >>> checker = OutputChecker([ ... lambda s: s.lower(), ... lambda s: s.replace('', ''), ... ]) >>> want = '''\ ... Usage: thundermonkey [options] [url] ... ... Options: ... -h display this help message ... ''' >>> got = '''\ ... usage: thundermonkey [options] [URL] ... ... options: ... -h Display this help message ... ''' >>> checker.check_output(want, got, 0) True Suppose we forgot that must be in upper case: >>> checker = OutputChecker([ ... lambda s: s.lower(), ... ]) >>> checker.check_output(want, got, 0) False The difference would show us that: >>> source = '''\ ... >>> print_help_message() ... ''' + want >>> example = doctest.Example(source, want) >>> print_(checker.output_difference(example, got, ... doctest.REPORT_NDIFF)) Differences (ndiff with -expected +actual): usage: thundermonkey [options] [url] - + options: -h display this help message It is possible to combine OutputChecker checkers for easy reuse: >>> address_and_time_checker = OutputChecker([ ... (re.compile('[0-9]*[.][0-9]* seconds'), ' seconds'), ... (re.compile('at 0x[0-9a-f]+'), 'at '), ... ]) >>> lowercase_checker = OutputChecker([ ... lambda s: s.lower(), ... ]) >>> combined_checker = address_and_time_checker + lowercase_checker >>> len(combined_checker.transformers) 3 Combining a checker with something else does not work: >>> lowercase_checker + 5 #doctest: +ELLIPSIS Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: ... zope.testing-4.1.2/src/zope/testing/__init__.py0000644000000000000000000000120212110747242017622 0ustar 00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation 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.testing-4.1.2/src/zope/testing/loggingsupport.py0000644000000000000000000000367412110747242021165 0ustar 00000000000000############################################################################## # # Copyright (c) 2004 Zope Foundation 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. # ############################################################################## import logging class Handler(logging.Handler): def __init__(self, *names, **kw): logging.Handler.__init__(self) self.names = names self.records = [] self.setLoggerLevel(**kw) def setLoggerLevel(self, level=1): self.level = level self.oldlevels = {} def emit(self, record): self.records.append(record) def clear(self): del self.records[:] def install(self): for name in self.names: logger = logging.getLogger(name) self.oldlevels[name] = logger.level logger.setLevel(self.level) logger.addHandler(self) def uninstall(self): for name in self.names: logger = logging.getLogger(name) logger.setLevel(self.oldlevels[name]) logger.removeHandler(self) def __str__(self): return '\n'.join( [("%s %s\n %s" % (record.name, record.levelname, '\n'.join([line for line in record.getMessage().split('\n') if line.strip()]) ) ) for record in self.records] ) class InstalledHandler(Handler): def __init__(self, *names, **kw): Handler.__init__(self, *names, **kw) self.install() zope.testing-4.1.2/src/zope/testing/loghandler.py0000644000000000000000000000511212110747242020206 0ustar 00000000000000############################################################################## # # Copyright (c) 2003 Zope Foundation 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. # ############################################################################## """logging handler for tests that check logging output. """ import logging class Handler(logging.Handler): """Handler for use with unittest.TestCase objects. The handler takes a TestCase instance as a constructor argument. It can be registered with one or more loggers and collects log records they generate. The assertLogsMessage() and failIfLogsMessage() methods can be used to check the logger output and causes the test to fail as appropriate. """ def __init__(self, testcase, propagate=False): logging.Handler.__init__(self) self.records = [] # loggers stores (logger, propagate) tuples self.loggers = [] self.closed = False self.propagate = propagate self.testcase = testcase def close(self): """Remove handler from any loggers it was added to.""" if self.closed: return for logger, propagate in self.loggers: logger.removeHandler(self) logger.propagate = propagate self.closed = True def add(self, name): """Add handler to logger named name.""" logger = logging.getLogger(name) old_prop = logger.propagate logger.addHandler(self) if self.propagate: logger.propagate = 1 else: logger.propagate = 0 self.loggers.append((logger, old_prop)) def emit(self, record): self.records.append(record) def assertLogsMessage(self, msg, level=None): for r in self.records: if r.getMessage() == msg: if level is not None and r.levelno == level: return msg = "No log message contained %r" % msg if level is not None: msg += " at level %d" % level self.testcase.fail(msg) def failIfLogsMessage(self, msg): for r in self.records: if r.getMessage() == msg: self.testcase.fail("Found log message %r" % msg) zope.testing-4.1.2/src/zope/testing/doctest/__init__.py0000644000000000000000000001766112110747242021307 0ustar 00000000000000__all__ = [ # 0, Option Flags 'register_optionflag', 'DONT_ACCEPT_TRUE_FOR_1', 'DONT_ACCEPT_BLANKLINE', 'NORMALIZE_WHITESPACE', 'ELLIPSIS', 'IGNORE_EXCEPTION_DETAIL', 'COMPARISON_FLAGS', 'REPORT_UDIFF', 'REPORT_CDIFF', 'REPORT_NDIFF', 'REPORT_ONLY_FIRST_FAILURE', 'REPORTING_FLAGS', # 1. Utility Functions # 2. Example & DocTest 'Example', 'DocTest', # 3. Doctest Parser 'DocTestParser', # 4. Doctest Finder 'DocTestFinder', # 5. Doctest Runner 'DocTestRunner', 'OutputChecker', 'DocTestFailure', 'UnexpectedException', 'DebugRunner', # 6. Test Functions 'testmod', 'testfile', 'run_docstring_examples', # 7. Tester 'Tester', # 8. Unittest Support 'DocTestSuite', 'DocFileSuite', 'DocFileTest', 'set_unittest_reportflags', # 9. Debugging Support 'script_from_examples', 'testsource', 'debug_src', 'debug', ] import sys if sys.version > '2.5': __all__.append('SKIP') # Tell people to use the builtin module instead. import warnings warnings.warn('zope.testing.doctest is deprecated in favour of ' 'the Python standard library doctest module', DeprecationWarning, stacklevel=2) # Patch to fix an error that makes subsequent tests fail after you have # returned unicode in a test. This is obviously not an issue in Python 3. # Reported as #8471: http://bugs.python.org/issue8471 import doctest if sys.version < '3': _org_SpoofOut = doctest._SpoofOut class _patched_SpoofOut(_org_SpoofOut): def truncate(self, size=None): _org_SpoofOut.truncate(self, size) if not self.buf: self.buf = '' doctest._SpoofOut = _patched_SpoofOut # Patching a unicode error that has been fixed in Python 2.6.5: import sys if sys.version < '2.6.5': import re doctest._encoding = getattr(sys.__stdout__, 'encoding', None) or 'utf-8' def _indent(s, indent=4): """ Add the given number of space characters to the beginning of every non-blank line in `s`, and return the result. If the string `s` is Unicode, it is encoded using the stdout encoding and the `backslashreplace` error handler. """ if isinstance(s, unicode): s = s.encode(doctest._encoding, 'backslashreplace') # This regexp matches the start of non-blank lines: return re.sub('(?m)^(?!$)', indent*' ', s) doctest._indent = _indent # Patch to fix tests that has mixed line endings: # Reported as #8473: http://bugs.python.org/issue8473 import os if sys.version < '2.5': from doctest import DocTestParser, master def _patched_testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser()): global master if package and not module_relative: raise ValueError("Package may only be specified for module-" "relative paths.") # Relativize the path if module_relative: package = _normalize_module(package) filename = _module_relative_path(package, filename) # If no name was given, then use the file's name. if name is None: name = os.path.basename(filename) # Assemble the globals. if globs is None: globs = {} else: globs = globs.copy() if extraglobs is not None: globs.update(extraglobs) if raise_on_error: runner = DebugRunner(verbose=verbose, optionflags=optionflags) else: runner = DocTestRunner(verbose=verbose, optionflags=optionflags) # Read the file, convert it to a test, and run it. s = open(filename, 'U').read() test = parser.get_doctest(s, globs, name, filename, 0) runner.run(test) if report: runner.summarize() if master is None: master = runner else: master.merge(runner) return runner.failures, runner.tries doctest.testfile = _patched_testfile from doctest import _normalize_module, _module_relative_path, DocFileCase def _patched_DocFileTest(path, module_relative=True, package=None, globs=None, parser=DocTestParser(), **options): if globs is None: globs = {} if package and not module_relative: raise ValueError("Package may only be specified for module-" "relative paths.") # Relativize the path. if module_relative: package = _normalize_module(package) path = _module_relative_path(package, path) # Find the file and read it. name = os.path.basename(path) doc = open(path, 'U').read() # Convert it to a test, and wrap it in a DocFileCase. test = parser.get_doctest(doc, globs, name, path, 0) return DocFileCase(test, **options) doctest.DocFileTest = _patched_DocFileTest else: def _patched_load_testfile(filename, package, module_relative, encoding=None): if module_relative: package = doctest._normalize_module(package, 3) filename = doctest._module_relative_path(package, filename) if hasattr(package, '__loader__'): if hasattr(package.__loader__, 'get_data'): file_contents = package.__loader__.get_data(filename) if encoding is not None: # Python 3 file_contents = file_contents.decode(encoding) # get_data() opens files as 'rb', so one must do the equivalent # conversion as universal newlines would do. return file_contents.replace(os.linesep, '\n'), filename if encoding: # Python 3: return open(filename, encoding=encoding).read(), filename else: return open(filename, 'U').read(), filename doctest._load_testfile = _patched_load_testfile # Patch to let the doctest have the globals of the testcase. This is slightly # evil, but Zopes doctests did this, and if we change it everything breaks. import unittest def _patched_setUp(self): test = self._dt_test self._dt_globs = test.globs.copy() if self._dt_setUp is not None: self._dt_setUp(test) def _patched_tearDown(self): test = self._dt_test if self._dt_tearDown is not None: self._dt_tearDown(test) test.globs.clear() test.globs.update(self._dt_globs) doctest.DocTestCase.setUp = _patched_setUp doctest.DocTestCase.tearDown = _patched_tearDown # Patch so you can set REPORT_ONLY_FIRST_FAILURE even if you have a DIFF flag # on the test. import sys from StringIO import StringIO def _patched_runTest(self): test = self._dt_test old = sys.stdout new = StringIO() optionflags = self._dt_optionflags if not (optionflags & doctest.REPORTING_FLAGS): # The option flags don't include any reporting flags, # so add the default reporting flags optionflags |= doctest._unittest_reportflags # This should work even if you have a diff flag: if doctest._unittest_reportflags & doctest.REPORT_ONLY_FIRST_FAILURE: optionflags |= doctest.REPORT_ONLY_FIRST_FAILURE runner = DocTestRunner(optionflags=optionflags, checker=self._dt_checker, verbose=False) try: runner.DIVIDER = "-"*70 failures, tries = runner.run( test, out=new.write, clear_globs=False) finally: sys.stdout = old if failures: raise self.failureException(self.format_failure(new.getvalue())) doctest.DocTestCase.runTest = _patched_runTest from doctest import * from doctest import DocFileTest # Not in doctests.__all__ for some reason. zope.testing-4.1.2/src/zope/testing/renormalizing/__init__.py0000644000000000000000000000542712110747242022517 0ustar 00000000000000############################################################################## # # Copyright (c) 2004 Zope Foundation 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. # ############################################################################## # # This file is a package rather than a module because we want # # import doctest # # to import the stdlib version of doctest rather than the deprecated # zope.testing.doctest, and # # from __future__ import absolute_import # # is not available on Python 2.4 which we still support. # ############################################################################## import doctest class OutputChecker(doctest.OutputChecker): """Pattern-normalizing outout checker """ def __init__(self, patterns): self.transformers = list(map(self._cook, patterns)) def __add__(self, other): if not isinstance(other, RENormalizing): return NotImplemented return RENormalizing(self.transformers + other.transformers) def _cook(self, pattern): if hasattr(pattern, '__call__'): return pattern regexp, replacement = pattern return lambda text: regexp.sub(replacement, text) def check_output(self, want, got, optionflags): if got == want: return True for transformer in self.transformers: want = transformer(want) got = transformer(got) return doctest.OutputChecker.check_output(self, want, got, optionflags) def output_difference(self, example, got, optionflags): want = example.want # If want is empty, use original outputter. This is useful # when setting up tests for the first time. In that case, we # generally use the differencer to display output, which we evaluate # by hand. if not want.strip(): return doctest.OutputChecker.output_difference( self, example, got, optionflags) # Dang, this isn't as easy to override as we might wish original = want for transformer in self.transformers: want = transformer(want) got = transformer(got) # temporarily hack example with normalized want: example.want = want result = doctest.OutputChecker.output_difference( self, example, got, optionflags) example.want = original return result RENormalizing = OutputChecker zope.testing-4.1.2/src/zope.testing.egg-info/namespace_packages.txt0000644000000000000000000000000512110747246023541 0ustar 00000000000000zope zope.testing-4.1.2/src/zope.testing.egg-info/not-zip-safe0000644000000000000000000000000112110747242021435 0ustar 00000000000000 zope.testing-4.1.2/src/zope.testing.egg-info/SOURCES.txt0000644000000000000000000000214212110747246021076 0ustar 00000000000000CHANGES.rst COPYRIGHT.txt LICENSE.txt MANIFEST.in README.rst bootstrap.py buildout.cfg setup.py tox.ini src/zope/__init__.py src/zope.testing.egg-info/PKG-INFO src/zope.testing.egg-info/SOURCES.txt src/zope.testing.egg-info/dependency_links.txt src/zope.testing.egg-info/namespace_packages.txt src/zope.testing.egg-info/not-zip-safe src/zope.testing.egg-info/requires.txt src/zope.testing.egg-info/top_level.txt src/zope/testing/__init__.py src/zope/testing/cleanup.py src/zope/testing/doctest.txt src/zope/testing/doctestunit.py src/zope/testing/exceptions.py src/zope/testing/formparser.py src/zope/testing/formparser.txt src/zope/testing/loggingsupport.py src/zope/testing/loggingsupport.txt src/zope/testing/loghandler.py src/zope/testing/module.py src/zope/testing/module.txt src/zope/testing/renormalizing.txt src/zope/testing/server.py src/zope/testing/setupstack.py src/zope/testing/setupstack.txt src/zope/testing/testrunner.py src/zope/testing/tests.py src/zope/testing/unicode.txt src/zope/testing/wait.py src/zope/testing/wait.txt src/zope/testing/doctest/__init__.py src/zope/testing/renormalizing/__init__.pyzope.testing-4.1.2/src/zope.testing.egg-info/PKG-INFO0000644000000000000000000013212612110747246020315 0ustar 00000000000000Metadata-Version: 1.1 Name: zope.testing Version: 4.1.2 Summary: Zope testing helpers Home-page: http://pypi.python.org/pypi/zope.testing Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: ************ zope.testing ************ .. contents:: This package provides a number of testing frameworks. cleanup Provides a mixin class for cleaning up after tests that make global changes. formparser An HTML parser that extracts form information. **Python 2 only** This is intended to support functional tests that need to extract information from HTML forms returned by the publisher. See formparser.txt. loggingsupport Support for testing logging code If you want to test that your code generates proper log output, you can create and install a handler that collects output. loghandler Logging handler for tests that check logging output. module Lets a doctest pretend to be a Python module. See module.txt. renormalizing Regular expression pattern normalizing output checker. Useful for doctests. server Provides a simple HTTP server compatible with the zope.app.testing functional testing API. Lets you interactively play with the system under test. Helpful in debugging functional doctest failures. **Python 2 only** setupstack A simple framework for automating doctest set-up and tear-down. See setupstack.txt. wait A small utility for dealing with timing non-determinism See wait.txt. Getting started *************** zope.testing uses buildout. To start, run ``python bootstrap.py``. It will create a number of directories and the ``bin/buildout`` script. Next, run ``bin/buildout``. It will create a test script for you. Now, run ``bin/test`` to run the zope.testing test suite. Detailed Documentation ********************** Parsing HTML Forms ================== Sometimes in functional tests, information from a generated form must be extracted in order to re-submit it as part of a subsequent request. The `zope.testing.formparser` module can be used for this purpose. NOTE formparser doesn't support Python 3. The scanner is implemented using the `FormParser` class. The constructor arguments are the page data containing the form and (optionally) the URL from which the page was retrieved: >>> import zope.testing.formparser >>> page_text = '''\ ... ...
... ... ... ... ...
... ... Just for fun, a second form, after specifying a base: ... ...
... ... ... ... ...
... ... ''' >>> parser = zope.testing.formparser.FormParser(page_text) >>> forms = parser.parse() >>> len(forms) 2 >>> forms.form1 is forms[0] True >>> forms.form1 is forms[1] False More often, the `parse()` convenience function is all that's needed: >>> forms = zope.testing.formparser.parse( ... page_text, "http://cgi.example.com/somewhere/form.html") >>> len(forms) 2 >>> forms.form1 is forms[0] True >>> forms.form1 is forms[1] False Once we have the form we're interested in, we can check form attributes and individual field values: >>> form = forms.form1 >>> form.enctype 'application/x-www-form-urlencoded' >>> form.method 'post' >>> keys = form.keys() >>> keys.sort() >>> keys ['do-it-now', 'f1', 'not-really', 'pick-two'] >>> not_really = form["not-really"] >>> not_really.type 'image' >>> not_really.value "Don't." >>> not_really.readonly False >>> not_really.disabled False Note that relative URLs are converted to absolute URLs based on the ```` element (if present) or using the base passed in to the constructor. >>> form.action 'http://cgi.example.com/cgi-bin/foobar.py' >>> not_really.src 'http://cgi.example.com/somewhere/dont.png' >>> forms[1].action 'http://www.example.com/base/sproing/sprung.html' >>> forms[1]["action"].src 'http://www.example.com/base/else.png' Fields which are repeated are reported as lists of objects that represent each instance of the field:: >>> field = forms[1]["multi"] >>> isinstance(field, list) True >>> [o.value for o in field] ['', ''] >>> [o.size for o in field] [2, 3] The ``