Zine

open source content publishing system


source: tests/__init__.py @ 1366:702961b91fa5

Revision 1366:702961b91fa5, 5.7 KB checked in by Jonas Fietz <info@…>, 2 years ago (diff)

enable specific tests again (bug through renaming)

Line 
1# -*- coding: utf-8 -*-
2"""
3    Zine Test Suite
4    ~~~~~~~~~~~~~~~
5
6    This is the Zine test suite. It collects all modules in the zine
7    package, builds a TestSuite with their doctests and executes them. It also
8    collects the tests from the text files in this directory (which are too
9    extensive to put them into the code without cluttering it up).
10
11    Please note that coverage reporting and doctest don't play well together
12    and your reports will probably miss some of the executed code. Doctest can
13    be patched to remove this incompatibility, the patch is at
14    http://tinyurl.com/doctest-patch
15
16    :copyright: (c) 2010 by the Zine Team, see AUTHORS for more details.
17    :license: BSD, see LICENSE for more details.
18"""
19
20import sys
21import os
22from os.path import join, dirname
23from unittest import TestSuite, TextTestRunner
24from doctest import DocTestSuite, DocFileSuite
25
26#: the modules in this list are not tested in a full run
27untested = ['zine.broken_plugins.hyphenation_en',
28            'zine.broken_plugins.hyphenation_en.hyphenate',
29            'zine.broken_plugins.notification']
30
31try:
32    import coverage
33except ImportError:
34    coverage = None
35
36
37def suite(modnames=[], return_covermods=False):
38    """Generate the test suite.
39
40    The first argument is a list of modules to be tested. If it is empty (which
41    it is by default), all sub-modules of the zine package are tested.
42    If the second argument is True, this function returns two objects: a
43    TestSuite instance and a list of the names of the tested modules. Otherwise
44    (which is the default) it only returns the former. This is done so that
45    this function can be used as setuptools' test_suite.
46    """
47
48    # the app object is used for two purposes:
49    # 1) plugins are not usable (i.e. not testable) without an initialised app
50    # 2) for functions that require an application object as argument, you can
51    #    write >>> my_function(app, ...) in the tests
52    # The instance directory of this object is located in the tests directory.
53    #
54    # setup isn't imported at module level because this way coverage
55    # can track the whole zine imports
56    from zine import setup
57    instance_path = join(dirname(__file__), 'instance')
58    app = setup(instance_path)
59
60    if return_covermods:
61        covermods = []
62    suite = TestSuite()
63
64    if modnames == []:
65        modnames = find_tp_modules()
66    test_files = os.listdir(dirname(__file__))
67    for modname in modnames:
68        if modname in untested:
69            continue
70
71        # the fromlist must contain something, otherwise the zine
72        # package is returned, not our module
73        try:
74            mod = __import__(modname, None, None, [''])
75        except ImportError:
76            # some plugins can have external dependencies (e.g. creoleparser,
77            # pygments) that are not installed on the machine the tests are
78            # run on. Therefore, just skip those (with an error message)
79            if 'plugins.' in modname:
80                sys.stderr.write('could not import plugin %s\n' % modname)
81                continue
82            else:
83                raise
84
85        suites = [DocTestSuite(mod, extraglobs={'app': app})]
86        filename = modname[5:] + '.txt'
87        if filename in test_files:
88            globs = {'app': app}
89            globs.update(mod.__dict__)
90            suites.append(DocFileSuite(filename, globs=globs))
91        for i, subsuite in enumerate(suites):
92            # skip modules without any tests
93            if subsuite.countTestCases():
94                suite.addTest(subsuite)
95                if return_covermods and i == 0:
96                    covermods.append(mod)
97    if return_covermods:
98        return suite, covermods
99    else:
100        return suite
101
102
103def find_tp_modules():
104    """Find all sub-modules of the zine package."""
105    modules = []
106    import zine
107    base = dirname(zine.__file__)
108    start = len(dirname(base))
109    if base != 'zine':
110        start += 1
111
112    for path, dirnames, filenames in os.walk(base):
113        for filename in filenames:
114            if filename.endswith('.py'):
115                fullpath = join(path, filename)
116                if filename == '__init__.py':
117                    stripped = fullpath[start:-12]
118                else:
119                    stripped = fullpath[start:-3]
120
121                modname = stripped.replace('/', '.')
122                modules.append(modname)
123    return modules
124
125
126def main():
127    from optparse import OptionParser
128    usage = ('Usage: %prog [option] [modules to be tested]\n'
129             'Modules names have to be given in the form utils.mail (without '
130             'zine.)\nIf no module names are given, all tests are run')
131    parser = OptionParser(usage=usage)
132    parser.add_option('-c', '--coverage', action='store_true', dest='coverage',
133                      help='show coverage information (slow!)')
134    parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
135                      default=False, help='show which tests are run')
136
137    options, args = parser.parse_args(sys.argv[1:])
138    modnames = ['zine.' + modname for modname in args]
139    if options.coverage:
140        if coverage is not None:
141            use_coverage = True
142        else:
143            sys.stderr.write("coverage information requires Ned Batchelder's "
144                             "coverage.py to be installed!\n")
145            sys.exit(1)
146    else:
147        use_coverage = False
148
149    if use_coverage:
150        coverage.erase()
151        coverage.start()
152        s, covermods = suite(modnames, True)
153    else:
154        s = suite(modnames)
155    TextTestRunner(verbosity=options.verbose + 1).run(s)
156    if use_coverage:
157        coverage.stop()
158        print '\n\n' + '=' * 25 + ' coverage information ' + '=' * 25
159        coverage.report(covermods)
160
161
162if __name__ == '__main__':
163    main()
Note: See TracBrowser for help on using the repository browser.