1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
#!/usr/bin/env python2.4
# Author: michele.simionato@gmail.com
"""Run doctest on text files. Examples of usage:
$ doct file.txt # run the tests in file.txt
$ doct -v file.txt # run the tests in verbose mode
$ doct -u file.txt # run the tests as unittests
$ doct directory # run all the tests in all the text files into directory.
For simplicity, this version is not recursive.
"""
import os, sys, doctest, time, textwrap, re, types, unittest
# regular expressions to identify code blocks of the form
#<scriptname.py>
#...
#</scriptname.py>
DOTNAME = r'\b[a-zA-Z_][\w\.]*', # identifier with or without dots
SCRIPT = re.compile(r'(?s)#<(%s)>(.*?)#</\1>' % DOTNAME)
# a simple utility to extract code blocks
def extractscript(txt):
for MO in SCRIPT.finditer(txt):
yield MO.group(1), textwrap.dedent(MO.group(2))
class TestRunner(object):
def __init__(self, verbose=False, unitest=False):
self.verbose = verbose
self.unitest = unitest
if unitest:
self.DocTestSuite = doctest.DocTestSuite
self.unitTestRunner = unittest.TextTestRunner(verbosity=verbose)
else:
self.docTestParser = doctest.DocTestParser()
self.docTestRunner = doctest.DocTestRunner(verbose=verbose)
def utest(self, fname, txt):
"""Converts doctests to unittests."""
# works by dynamically generating a module with a suitable docstring
suite = self.DocTestSuite(types.ModuleType(fname, txt))
self.unitTestRunner.run(suite)
return ''
def dtest(self, fname, txt):
"""Making dtest similar to utest."""
dt = self.docTestParser.get_doctest(txt, {}, fname, fname, 0)
t0 = time.clock()
failed, total = self.docTestRunner.run(dt)
if failed:
return ''
else:
return "%s: %s tests passed in %s seconds\n" % (
fname, total, time.clock() - t0)
def run(self, txt='', fname=''):
if fname:
txt += file(fname, 'U').read()
else:
fname = '<current-buffer>'
scriptnames = []; scriptdict = {}
for scriptname, script in extractscript(txt): # read scripts
if scriptname not in scriptnames:
scriptdict[scriptname] = script
scriptnames.append(scriptname)
else:
scriptdict[scriptname] += script
for scriptname in scriptnames: # save scripts
code = '# ' + scriptname + scriptdict[scriptname]
print >> file(scriptname, 'w'), code
if self.unitest:
return self.utest(fname, txt)
else:
return self.dtest(fname, txt)
if __name__=='__main__':
# strip the option arguments
args = [arg for arg in sys.argv[1:] if not arg.startswith("-")]
if not args: # print usage message
print __doc__
if len(args) > 1:
print "Too many args"
else: # run
arg = args[0]
verbose = "-v" in sys.argv
unitest = "-u" in sys.argv
if os.path.isdir(arg):
for fname in os.listdir(arg):
f = os.path.join(arg, fname)
print TestRunner(verbose, unitest).run(fname=f)
elif os.path.isfile(arg):
print TestRunner(verbose, unitest).run(fname=args[0])
else:
raise IOError("File %s not found" % arg)
|