Last active
August 29, 2015 14:08
-
-
Save tomviner/aac26d5ac93a5d34106c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import unicode_literals | |
class Explode(): | |
def __repr__(self): | |
return '(1/0)' | |
explode = Explode() | |
class Expr(object): | |
def __init__(self, percent_expr, logic_op, bool_expr, percent_first, percent_char): | |
percent_expr = percent_expr.replace('%', percent_char) | |
self.percent_expr = '({} {} {})'.format(*percent_expr) | |
self.logic_op = logic_op | |
self.bool_expr = bool_expr | |
self.percent_first = percent_first | |
self.percent_char = percent_char | |
def expr(self, explode_per=False): | |
percent_expr = self.percent_expr | |
if explode_per: | |
percent_expr = explode | |
if not self.percent_first: | |
return '{} {} {}'.format(percent_expr, self.logic_op, self.bool_expr) | |
return '{} {} {}'.format(self.bool_expr, self.logic_op, percent_expr) | |
def asserts_true(self): | |
return bool(eval(self.expr())) | |
def percent_is_evaled(self): | |
try: | |
eval(self.expr(explode_per=True)) | |
except ZeroDivisionError: | |
return True | |
else: | |
return False | |
def function_name(self): | |
return (self.expr().replace('-', 'sub') | |
.replace(' ', '_') .replace('(', '') | |
.replace(')', '') .replace('%', 'mod')) | |
def function_docstring(self): | |
return 'Asserts: {}. Percent {} evaled'.format(self.asserts_true(), | |
'*is*' if self.percent_is_evaled() else 'is *not*') | |
def short_cirtuit_expr(self): | |
"Trim off unevaled sub-expression" | |
if self.percent_is_evaled(): | |
return self.expr() | |
return '({})'.format(self.bool_expr) | |
def getmsg(self): | |
if self.asserts_true(): | |
return 'getmsg(f, must_pass=True)' | |
if not self.percent_is_evaled(): | |
return 'assert getmsg(f) == "assert {}"'.format(self.short_cirtuit_expr()) | |
return """ | |
try: | |
getmsg(f) == "assert {}" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {{!r}}".format(e)) | |
""".strip().format(self.short_cirtuit_expr()) | |
def __unicode__(self): | |
return """ | |
def test_{}(self): | |
"{}" | |
def f(): | |
assert {} | |
{} | |
""".strip('\n').format(self.function_name(), self.function_docstring(), self.expr(), self.getmsg()) | |
def __repr__(self): | |
return self.expr() | |
@property | |
def ordering(self): | |
return self.percent_char, self.asserts_true(), self.percent_is_evaled() | |
def __cmp__(self, other): | |
return cmp(self.ordering, other.ordering) | |
def __hash__(self): | |
return hash(self.expr()) | |
def generate_all_cases(): | |
for logic_op in ('and', 'or'): | |
for percent_first in (True, False): | |
for bool_expr in ('True', 'False'): | |
# eval as 1 and 0 | |
for percent_expr in ('3%2', '1%1'): | |
# repeat all with '-' to check that expressions are correct, | |
# once the ValueError is fixed. | |
for percent_char in ('%', '-'): | |
yield Expr(percent_expr, logic_op, bool_expr, percent_first, percent_char) | |
def main(): | |
new_tests = '\n'.join(map(unicode, | |
sorted(generate_all_cases()) | |
)) | |
print new_tests | |
test_source_in_fn = "pytest-git-remote-2/testing/test_assertrewrite_input.py" | |
test_source_out_fn = "pytest-git-remote-2/testing/test_assertrewrite_output.py" | |
test_source = open(test_source_in_fn).read() | |
test_source = test_source.replace('# percent test here', new_tests) | |
open(test_source_out_fn, 'w').write(test_source) | |
def test_unique_cases(): | |
cases = list(generate_all_cases()) | |
assert len(cases) == len(set(cases)) | |
if __name__ == '__main__': | |
import pytest | |
fails = pytest.main(__file__) | |
assert not fails | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
# generate rewritten code using `meta`, the ast reverse parsing tool: | |
# https://srossross.github.io/Meta/html/api/asttools.html#meta.asttools.python_source | |
# edit rewrite in testing/test_assertrewrite.py | |
def rewrite(src): | |
tree = ast.parse(src) | |
rewrite_asserts(tree) | |
# insert these 2 lines: | |
import meta | |
meta.asttools.python_source(tree) # remove '@'s to enable running | |
return tree | |
# The test being rewritten here: | |
class TestAssertionRewriteCompoundAssertWithPercent: | |
def test_and_or_percent(self): | |
# issue 615 - ValueError on compound assert with percent | |
def f(): | |
assert 3 % 2 and False | |
assert getmsg(f) == "assert ((3 % 2) and False)" | |
See inline comments below showing how ValueError arises: | |
""" | |
import __builtin__ as py_builtins | |
import _pytest.assertion.rewrite as pytest_ar | |
def f(): | |
py_assert1 = [] | |
py_assert2 = 3 | |
py_assert4 = 2 | |
py_assert6 = (py_assert2 % py_assert4) | |
py_assert0 = py_assert6 | |
if py_assert6: | |
py_assert0 = False | |
if (not py_assert0): | |
# as expected py_format7 recieves a `%` here (the `%%` becomes a single `%` after formatting) | |
py_format7 = ('(%(py3)s %% %(py5)s)' % {'py3':pytest_ar._saferepr(py_assert2), 'py5':pytest_ar._saferepr(py_assert4)}) | |
# py_assert1 here gains the item with the `%`: | |
py_assert1.append(py_format7) | |
if py_assert6: | |
py_format9 = ('%(py8)s' % {'py8':pytest_ar._saferepr(False) if (('False' in py_builtins.locals()) or pytest_ar._should_repr_global_name(False)) else 'False'}) | |
py_assert1.append(py_format9) | |
# Here pytest_ar._format_boolop(py_assert1, 0) allows the `%` to pass through unescaped | |
# then ValueErrors when used as a percent format string, which in this case | |
# should contain no unescaped percents, as an empty formatting dict is supplied. | |
py_format10 = (pytest_ar._format_boolop(py_assert1, 0) % {}) | |
py_format12 = ('assert %(py11)s' % {'py11':py_format10}) | |
raise AssertionError(pytest_ar._format_explanation(py_format12)) | |
py_assert0 = py_assert1 = py_assert2 = py_assert4 = py_assert6 = None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pytest | |
from test_assertrewrite import getmsg | |
class TestAssertionRewriteCompoundAssertWithPercent: | |
# start inserted code | |
# percent test here | |
# end inserted code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pytest | |
from test_assertrewrite import getmsg | |
class TestAssertionRewriteCompoundAssertWithPercent: | |
# start inserted code | |
def test_False_and_3_mod_2(self): | |
"Asserts: False. Percent is *not* evaled" | |
def f(): | |
assert False and (3 % 2) | |
assert getmsg(f) == "assert (False)" | |
def test_False_and_1_mod_1(self): | |
"Asserts: False. Percent is *not* evaled" | |
def f(): | |
assert False and (1 % 1) | |
assert getmsg(f) == "assert (False)" | |
def test_True_and_1_mod_1(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert True and (1 % 1) | |
try: | |
getmsg(f) == "assert True and (1 % 1)" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_1_mod_1_and_True(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert (1 % 1) and True | |
try: | |
getmsg(f) == "assert (1 % 1) and True" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_3_mod_2_and_False(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert (3 % 2) and False | |
try: | |
getmsg(f) == "assert (3 % 2) and False" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_1_mod_1_and_False(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert (1 % 1) and False | |
try: | |
getmsg(f) == "assert (1 % 1) and False" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_False_or_1_mod_1(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert False or (1 % 1) | |
try: | |
getmsg(f) == "assert False or (1 % 1)" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_1_mod_1_or_False(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert (1 % 1) or False | |
try: | |
getmsg(f) == "assert (1 % 1) or False" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_True_or_3_mod_2(self): | |
"Asserts: True. Percent is *not* evaled" | |
def f(): | |
assert True or (3 % 2) | |
getmsg(f, must_pass=True) | |
def test_True_or_1_mod_1(self): | |
"Asserts: True. Percent is *not* evaled" | |
def f(): | |
assert True or (1 % 1) | |
getmsg(f, must_pass=True) | |
def test_True_and_3_mod_2(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert True and (3 % 2) | |
getmsg(f, must_pass=True) | |
def test_3_mod_2_and_True(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert (3 % 2) and True | |
getmsg(f, must_pass=True) | |
def test_False_or_3_mod_2(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert False or (3 % 2) | |
getmsg(f, must_pass=True) | |
def test_3_mod_2_or_True(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert (3 % 2) or True | |
getmsg(f, must_pass=True) | |
def test_1_mod_1_or_True(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert (1 % 1) or True | |
getmsg(f, must_pass=True) | |
def test_3_mod_2_or_False(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert (3 % 2) or False | |
getmsg(f, must_pass=True) | |
def test_False_and_3_sub_2(self): | |
"Asserts: False. Percent is *not* evaled" | |
def f(): | |
assert False and (3 - 2) | |
assert getmsg(f) == "assert (False)" | |
def test_False_and_1_sub_1(self): | |
"Asserts: False. Percent is *not* evaled" | |
def f(): | |
assert False and (1 - 1) | |
assert getmsg(f) == "assert (False)" | |
def test_True_and_1_sub_1(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert True and (1 - 1) | |
try: | |
getmsg(f) == "assert True and (1 - 1)" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_1_sub_1_and_True(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert (1 - 1) and True | |
try: | |
getmsg(f) == "assert (1 - 1) and True" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_3_sub_2_and_False(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert (3 - 2) and False | |
try: | |
getmsg(f) == "assert (3 - 2) and False" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_1_sub_1_and_False(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert (1 - 1) and False | |
try: | |
getmsg(f) == "assert (1 - 1) and False" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_False_or_1_sub_1(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert False or (1 - 1) | |
try: | |
getmsg(f) == "assert False or (1 - 1)" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_1_sub_1_or_False(self): | |
"Asserts: False. Percent *is* evaled" | |
def f(): | |
assert (1 - 1) or False | |
try: | |
getmsg(f) == "assert (1 - 1) or False" | |
except ValueError as e: | |
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e)) | |
def test_True_or_3_sub_2(self): | |
"Asserts: True. Percent is *not* evaled" | |
def f(): | |
assert True or (3 - 2) | |
getmsg(f, must_pass=True) | |
def test_True_or_1_sub_1(self): | |
"Asserts: True. Percent is *not* evaled" | |
def f(): | |
assert True or (1 - 1) | |
getmsg(f, must_pass=True) | |
def test_True_and_3_sub_2(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert True and (3 - 2) | |
getmsg(f, must_pass=True) | |
def test_3_sub_2_and_True(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert (3 - 2) and True | |
getmsg(f, must_pass=True) | |
def test_False_or_3_sub_2(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert False or (3 - 2) | |
getmsg(f, must_pass=True) | |
def test_3_sub_2_or_True(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert (3 - 2) or True | |
getmsg(f, must_pass=True) | |
def test_1_sub_1_or_True(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert (1 - 1) or True | |
getmsg(f, must_pass=True) | |
def test_3_sub_2_or_False(self): | |
"Asserts: True. Percent *is* evaled" | |
def f(): | |
assert (3 - 2) or False | |
getmsg(f, must_pass=True) | |
# end inserted code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ tox -e py27 -- testing/test_assertrewrite_output.py -k TestAssertionRewriteCompoundAssertWithPercent -v | |
GLOB sdist-make: setup.py | |
py27 inst-nodeps: .tox/dist/pytest-2.7.0.dev1.zip | |
py27 runtests: PYTHONHASHSEED='2078814091' | |
py27 runtests: commands[0] | py.test --lsof -rfsxX --junitxml=.tox/py27/log/junit-py27.xml test_assertrewrite_output.py -k TestAssertionRewriteCompoundAssertWithPercent -v | |
===================================================================== test session starts ===================================================================== | |
platform linux2 -- Python 2.7.6 -- py-1.4.26 -- pytest-2.7.0.dev1 -- .tox/py27/bin/python2.7 | |
collected 32 items | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_and_3_mod_2 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_and_1_mod_1 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_and_1_mod_1 xfail | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_mod_1_and_True xfail | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_mod_2_and_False xfail | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_mod_1_and_False xfail | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_or_1_mod_1 xfail | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_mod_1_or_False xfail | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_or_3_mod_2 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_or_1_mod_1 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_and_3_mod_2 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_mod_2_and_True PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_or_3_mod_2 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_mod_2_or_True PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_mod_1_or_True PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_mod_2_or_False PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_and_3_sub_2 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_and_1_sub_1 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_and_1_sub_1 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_sub_1_and_True PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_sub_2_and_False PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_sub_1_and_False PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_or_1_sub_1 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_sub_1_or_False PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_or_3_sub_2 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_or_1_sub_1 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_and_3_sub_2 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_sub_2_and_True PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_or_3_sub_2 PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_sub_2_or_True PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_sub_1_or_True PASSED | |
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_sub_2_or_False PASSED | |
-------------------- generated xml file: .tox/py27/log/junit-py27.xml --------------------- | |
=================================================================== short test summary info =================================================================== | |
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_True_and_1_mod_1 | |
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 16",) | |
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_1_mod_1_and_True | |
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 7",) | |
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_3_mod_2_and_False | |
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 7",) | |
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_1_mod_1_and_False | |
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 7",) | |
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_False_or_1_mod_1 | |
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 16",) | |
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_1_mod_1_or_False | |
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 7",) | |
============================================================ 26 passed, 6 xfailed in 0.74 seconds ============================================================= | |
___________________________________________________________________________ summary ___________________________________________________________________________ | |
py27: commands succeeded | |
congratulations :) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment