0.2.0 - docstring support
This commit is contained in:
parent
48eaa947b6
commit
7a7628abba
2
setup.py
2
setup.py
@ -38,7 +38,7 @@ def get_packages():
|
||||
return packages
|
||||
|
||||
setup(name='steadymark',
|
||||
version='0.1.4',
|
||||
version='0.2.0',
|
||||
description=(u'Markdown-based test runner for python. '
|
||||
'Good for github projects'),
|
||||
author=u'Gabriel Falcao',
|
||||
|
@ -35,8 +35,7 @@ from doctest import (
|
||||
DocTestParser,
|
||||
Example,
|
||||
DocTest,
|
||||
DocTestRunner,
|
||||
TestResults,
|
||||
DebugRunner,
|
||||
)
|
||||
from datetime import datetime
|
||||
|
||||
@ -49,6 +48,11 @@ from misaka import (
|
||||
)
|
||||
|
||||
|
||||
class SteadyMarkDoctestRunner(DebugRunner):
|
||||
def report_unexpected_exception(self, out, test, example, exc_info):
|
||||
raise exc_info
|
||||
|
||||
|
||||
class MarkdownTest(object):
|
||||
def __init__(self, title, raw_code):
|
||||
self.title = title
|
||||
@ -71,23 +75,33 @@ class MarkdownTest(object):
|
||||
else:
|
||||
self.code = compile(raw_code, "@STEADYMARK@", "exec")
|
||||
|
||||
def _run_raw(self):
|
||||
return eval(self.code)
|
||||
|
||||
def _run_doctest(self):
|
||||
if not isinstance(self.code, DocTest):
|
||||
raise TypeError(
|
||||
"Attempt to run a non-doctest as doctest: %r" % self.code)
|
||||
|
||||
runner = SteadyMarkDoctestRunner(verbose=False)
|
||||
return runner.run(self.code)
|
||||
|
||||
def run(self):
|
||||
before = datetime.now()
|
||||
failure = None
|
||||
if isinstance(self.code, DocTest):
|
||||
runner = DocTestRunner()
|
||||
result = runner.run(self.code)
|
||||
after = datetime.now()
|
||||
return result, before, after
|
||||
else:
|
||||
try:
|
||||
eval(self.code)
|
||||
except:
|
||||
failure = sys.exc_info()
|
||||
result = None
|
||||
|
||||
try:
|
||||
if isinstance(self.code, DocTest):
|
||||
result = self._run_doctest()
|
||||
else:
|
||||
result = self._run_raw()
|
||||
except:
|
||||
failure = sys.exc_info()
|
||||
|
||||
after = datetime.now()
|
||||
|
||||
return failure, before, after
|
||||
return result, failure, before, after
|
||||
|
||||
|
||||
class SteadyMark(BaseRenderer):
|
||||
@ -131,10 +145,6 @@ class SteadyMark(BaseRenderer):
|
||||
md.render(markdown)
|
||||
return renderer
|
||||
|
||||
def run(self):
|
||||
for test in self.tests:
|
||||
test.run()
|
||||
|
||||
|
||||
class Runner(object):
|
||||
def __init__(self, filename=None, text=u''):
|
||||
@ -150,6 +160,10 @@ class Runner(object):
|
||||
self.filename = filename
|
||||
self.text = text
|
||||
|
||||
def print_white(self, text, indentation=0):
|
||||
for line in text.splitlines():
|
||||
print "{1}\033[1;37m{0}\033[0m".format(line, ' ' * indentation)
|
||||
|
||||
def print_red(self, text, indentation=0):
|
||||
for line in text.splitlines():
|
||||
print "{1}\033[1;31m{0}\033[0m".format(line, ' ' * indentation)
|
||||
@ -158,69 +172,73 @@ class Runner(object):
|
||||
for line in text.splitlines():
|
||||
print "{1}\033[1;32m{0}\033[0m".format(line, ' ' * indentation)
|
||||
|
||||
def print_yellow(self, text, indentation=0):
|
||||
for line in text.splitlines():
|
||||
print "{1}\033[1;33m{0}\033[0m".format(line, ' ' * indentation)
|
||||
|
||||
def format_ms(self, ms):
|
||||
ms = int(ms)
|
||||
if ms < 1000:
|
||||
return ""
|
||||
|
||||
return "\033[1;33m{0}ms\033[0m".format(ms)
|
||||
|
||||
def format_traceback(self, title, failure):
|
||||
def format_traceback(self, test, failure):
|
||||
exc, exc_instance, tb = failure
|
||||
# formatted_tb = traceback.format_exc(exc_instance).strip()
|
||||
# if 'None' == formatted_tb:
|
||||
formatted_tb = ''.join(traceback.format_tb(tb))
|
||||
formatted_tb = formatted_tb.replace(
|
||||
u'File "@STEADYMARK@',
|
||||
u'In the test "@STEADYMARK@',
|
||||
)
|
||||
formatted_tb = formatted_tb.replace(
|
||||
u'@STEADYMARK@', unicode(test.title))
|
||||
|
||||
formatted_tb = traceback.format_exc(exc_instance).strip()
|
||||
if 'None' == formatted_tb:
|
||||
formatted_tb = ''.join(traceback.format_tb(tb))
|
||||
formatted_tb = formatted_tb.replace(
|
||||
u'File "@STEADYMARK@',
|
||||
u'In the test "@STEADYMARK@',
|
||||
)
|
||||
formatted_tb = formatted_tb.replace(
|
||||
u'@STEADYMARK@', unicode(title))
|
||||
|
||||
return u'{0} {1}\n{2}'.format(
|
||||
return u'{0} \033[1;36m{1}\n{2}\n'.format(
|
||||
exc.__name__,
|
||||
exc_instance,
|
||||
formatted_tb,
|
||||
)
|
||||
|
||||
def report_doctest_result(self, test, result, before, after):
|
||||
# shift = before - after
|
||||
# ms = self.format_ms(shift.microseconds / 1000)
|
||||
# import ipdb;ipdb.set_trace()
|
||||
pass
|
||||
|
||||
def report_raw_test_result(self, test, failure, before, after):
|
||||
shift = before - after
|
||||
ms = self.format_ms(shift.microseconds / 1000)
|
||||
lines = test.raw_code.splitlines()
|
||||
|
||||
if not failure:
|
||||
return self.print_green('\xe2\x9c\x93 {0}'.format(ms))
|
||||
def report_success(self, test, shift, ms):
|
||||
self.print_green('\xe2\x9c\x93 {0}'.format(ms))
|
||||
print
|
||||
|
||||
def report_failure(self, test, failure, shift, ms):
|
||||
self.print_red('\xe2\x9c\x97 {0}'.format(ms))
|
||||
exc, exc_instance, tb = failure
|
||||
|
||||
formatted_tb = self.format_traceback(test.title, failure)
|
||||
formatted_tb = self.format_traceback(test, failure)
|
||||
|
||||
tb = tb.tb_next
|
||||
if tb:
|
||||
line = lines[tb.tb_lineno - 1]
|
||||
self.print_red("{0} {1}".format(formatted_tb, line))
|
||||
elif issubclass(exc, SyntaxError):
|
||||
self.print_red(formatted_tb, indentation=2)
|
||||
self.print_red(formatted_tb, indentation=2)
|
||||
|
||||
header = "original code:"
|
||||
header_length = len(header)
|
||||
self.print_white("*" * header_length)
|
||||
self.print_white(header)
|
||||
self.print_white("*" * header_length)
|
||||
|
||||
self.print_yellow(test.raw_code, indentation=2)
|
||||
print
|
||||
|
||||
def report_test_result(self, test, failure, before, after):
|
||||
shift = before - after
|
||||
ms = self.format_ms(shift.microseconds / 1000)
|
||||
|
||||
if not failure:
|
||||
return self.report_success(test, shift, ms)
|
||||
|
||||
return self.report_failure(test, failure, shift, ms)
|
||||
|
||||
def run(self):
|
||||
if self.filename:
|
||||
print "Running tests from {0}".format(self.filename)
|
||||
|
||||
for test in self.steadymark.tests:
|
||||
sys.stdout.write("{0} ".format(test.title))
|
||||
result, before, after = test.run()
|
||||
if isinstance(result, TestResults):
|
||||
self.report_doctest_result(test, result, before, after)
|
||||
else:
|
||||
self.report_raw_test_result(test, result, before, after)
|
||||
title = "{0} ".format(test.title)
|
||||
title_length = len(title)
|
||||
print "." * title_length
|
||||
sys.stdout.write(title)
|
||||
result, failure, before, after = test.run()
|
||||
self.report_test_result(test, failure, before, after)
|
||||
|
||||
return self.steadymark
|
||||
|
||||
|
@ -23,3 +23,4 @@
|
||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
import sure
|
||||
|
68
tests/unit/test_runner.py
Normal file
68
tests/unit/test_runner.py
Normal file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# <steadymark - markdown-based test runner for python>
|
||||
# Copyright (C) <2012> Gabriel Falcão <gabriel@nacaolivre.org>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation
|
||||
# files (the "Software"), to deal in the Software without
|
||||
# restriction, including without limitation the rights to use,
|
||||
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the
|
||||
# Software is furnished to do so, subject to the following
|
||||
# conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
from steadymark import SteadyMark
|
||||
|
||||
|
||||
def test_find_doctest_code_with_titles():
|
||||
(u"SteadyMark should find doctest and use the "
|
||||
"previous header as title")
|
||||
|
||||
md = u"""# test 1
|
||||
a paragraph
|
||||
|
||||
```python
|
||||
>>> raise TypeError('boom')
|
||||
```
|
||||
"""
|
||||
|
||||
sm = SteadyMark.inspect(md)
|
||||
test1 = sm.tests[0]
|
||||
result, (_, failure, tb), before, after = test1.run()
|
||||
|
||||
test1.title.should.equal("test 1")
|
||||
failure.should.be.a(TypeError)
|
||||
"boom".should.be.within(unicode(failure))
|
||||
|
||||
|
||||
def test_find_python_code_with_titles():
|
||||
(u"SteadyMark should find python code and use the "
|
||||
"previous header as title")
|
||||
|
||||
md = u"""# test 1
|
||||
a paragraph
|
||||
|
||||
```python
|
||||
raise ValueError('boom')
|
||||
```
|
||||
"""
|
||||
|
||||
sm = SteadyMark.inspect(md)
|
||||
test1 = sm.tests[0]
|
||||
result, (_, failure, tb), before, after = test1.run()
|
||||
|
||||
test1.title.should.equal("test 1")
|
||||
failure.should.be.a(ValueError)
|
||||
"boom".should.be.within(unicode(failure))
|
Loading…
Reference in New Issue
Block a user