0001"""
0002More-or-less like doctest, except with Logo
0003"""
0004
0005import os
0006import doctest
0007import sys
0008import traceback
0009from cStringIO import StringIO
0010import reader
0011import interpreter
0012from pylogo import builtins
0013from pylogo import oobuiltins
0014
0015def testfile(filename, globs=None, name=None,
0016 verbose=None, optionflags=0,
0017 report=True, master=None,
0018 interp=None,
0019 verbose_summary=False):
0020 if globs is None:
0021 globs = {}
0022 if interp is None:
0023 interp = interpreter.RootFrame()
0024 interp.import_module(builtins)
0025 interp.import_module(oobuiltins)
0026 interp.vars.update(globs)
0027 if name is None:
0028 name = os.path.basename(filename)
0029 runner = LogoRunner(interp, verbose=verbose,
0030 optionflags=optionflags)
0031 s = open(filename).read()
0032 parser = doctest.DocTestParser()
0033 test = parser.get_doctest(s, globs, name,
0034 filename, 0)
0035 runner.run(test)
0036 if report:
0037 runner.summarize(verbose or verbose_summary)
0038 if master is None:
0039 master = runner
0040 else:
0041 master.merge(runner)
0042 return runner.failures, runner.tries
0043
0044class LogoRunner(doctest.DocTestRunner):
0045
0046 def __init__(self, interpreter, *args, **kw):
0047 doctest.DocTestRunner.__init__(self, *args, **kw)
0048 self.interpreter = interpreter
0049
0050 def _DocTestRunner__run(self, test, compileflags, out):
0051 failures, tries = self._run(test, compileflags, out)
0052 self._DocTestRunner__record_outcome(test, failures, tries)
0053 return failures, tries
0054
0055
0056
0057
0058
0059 def _DocTestRunner__run(self, test, compileflags, out):
0060 """
0061 Run the examples in `test`. Write the outcome of each example
0062 with one of the `DocTestRunner.report_*` methods, using the
0063 writer function `out`. `compileflags` is the set of compiler
0064 flags that should be used to execute examples. Return a tuple
0065 `(f, t)`, where `t` is the number of examples tried, and `f`
0066 is the number of examples that failed. The examples are run
0067 in the namespace `test.globs`.
0068 """
0069
0070 failures = tries = 0
0071
0072
0073
0074 original_optionflags = self.optionflags
0075
0076 SUCCESS, FAILURE, BOOM = range(3)
0077
0078 check = self._checker.check_output
0079
0080
0081 for examplenum, example in enumerate(test.examples):
0082
0083
0084
0085 quiet = (self.optionflags & doctest.REPORT_ONLY_FIRST_FAILURE and
0086 failures > 0)
0087
0088
0089 self.optionflags = original_optionflags
0090 if example.options:
0091 for (optionflag, val) in example.options.items():
0092 if val:
0093 self.optionflags |= optionflag
0094 else:
0095 self.optionflags &= ~optionflag
0096
0097
0098 tries += 1
0099 if not quiet:
0100 self.report_start(out, test, example)
0101
0102
0103
0104
0105 filename = '<doctest %s[%d]>' % (test.name, examplenum)
0106
0107
0108
0109
0110 try:
0111
0112 self.run_example(example.source, filename, compileflags, test.globs)
0113 self.debugger.set_continue()
0114 exception = None
0115 except KeyboardInterrupt:
0116 raise
0117 except:
0118 exception = sys.exc_info()
0119 self.debugger.set_continue()
0120
0121 got = self._fakeout.getvalue()
0122 self._fakeout.truncate(0)
0123 outcome = FAILURE
0124
0125
0126
0127 if exception is None:
0128 if check(example.want, got, self.optionflags):
0129 outcome = SUCCESS
0130
0131
0132 else:
0133 exc_info = sys.exc_info()
0134 exc_msg = traceback.format_exception_only(*exc_info[:2])[-1]
0135 if not quiet:
0136 got += doctest._exception_traceback(exc_info)
0137
0138
0139
0140 if example.exc_msg is None:
0141 outcome = BOOM
0142
0143
0144 elif check(example.exc_msg, exc_msg, self.optionflags):
0145 outcome = SUCCESS
0146
0147
0148 elif self.optionflags & doctest.IGNORE_EXCEPTION_DETAIL:
0149 m1 = re.match(r'[^:]*:', example.exc_msg)
0150 m2 = re.match(r'[^:]*:', exc_msg)
0151 if m1 and m2 and check(m1.group(0), m2.group(0),
0152 self.optionflags):
0153 outcome = SUCCESS
0154
0155
0156 if outcome is SUCCESS:
0157 if not quiet:
0158 self.report_success(out, test, example, got)
0159 elif outcome is FAILURE:
0160 if not quiet:
0161 self.report_failure(out, test, example, got)
0162 failures += 1
0163 elif outcome is BOOM:
0164 if not quiet:
0165 self.report_unexpected_exception(out, test, example,
0166 exc_info)
0167 failures += 1
0168 else:
0169 assert False, ("unknown outcome", outcome)
0170
0171
0172 self.optionflags = original_optionflags
0173
0174
0175 self._DocTestRunner__record_outcome(test, failures, tries)
0176 return failures, tries
0177
0178 prompts = {
0179 None: '',
0180 'to': '',
0181 '[': '',
0182 '(': '',
0183 'func': '',
0184 }
0185
0186 def run_example(self, source, filename,
0187 compileflags, globs):
0188 input = StringIO(source)
0189 input = reader.TrackingStream(input, name=filename)
0190 tokenizer = reader.FileTokenizer(
0191 input, prompt=self.prompts)
0192 interp = self.interpreter
0193 interp.push_tokenizer(tokenizer)
0194 try:
0195 v = interp.expr_top()
0196 if v is not None:
0197 print builtins.logo_repr(v)
0198 finally:
0199 interp.pop_tokenizer()
0200
0201if __name__ == '__main__':
0202 filenames = sys.argv[1:]
0203 for filename in filenames:
0204 if filename.startswith('-'):
0205 continue
0206 print "testing", filename
0207 testfile(filename)