diff --git a/_pytest/assertion.py b/_pytest/assertion.py index 9c7143bb8..8f09e6661 100644 --- a/_pytest/assertion.py +++ b/_pytest/assertion.py @@ -50,8 +50,9 @@ except NameError: def pytest_assertrepr_compare(op, left, right): """return specialised explanations for some operators/operands""" - left_repr = py.io.saferepr(left, maxsize=30) - right_repr = py.io.saferepr(right, maxsize=30) + width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op + left_repr = py.io.saferepr(left, maxsize=width/2) + right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) summary = '%s %s %s' % (left_repr, op, right_repr) issequence = lambda x: isinstance(x, (list, tuple)) @@ -71,6 +72,9 @@ def pytest_assertrepr_compare(op, left, right): elif isdict(left) and isdict(right): explanation = _diff_text(py.std.pprint.pformat(left), py.std.pprint.pformat(right)) + elif op == 'not in': + if istext(left) and istext(right): + explanation = _notin_text(left, right) except py.builtin._sysex: raise except: @@ -154,3 +158,11 @@ def _compare_eq_set(left, right): for item in diff_right: explanation.append(py.io.saferepr(item)) return explanation + + +def _notin_text(term, text): + index = text.find(term) + head = text[:index] + tail = text[index+len(term):] + correct_text = head + tail + return _diff_text(correct_text, text) diff --git a/doc/example/assertion/failure_demo.py b/doc/example/assertion/failure_demo.py index 74a2b3c70..c29323bc7 100644 --- a/doc/example/assertion/failure_demo.py +++ b/doc/example/assertion/failure_demo.py @@ -77,6 +77,22 @@ class TestSpecialisedExplanations(object): def test_in_list(self): assert 1 in [0, 2, 3, 4, 5] + def test_not_in_text_multiline(self): + text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail' + assert 'foo' not in text + + def test_not_in_text_single(self): + text = 'single foo line' + assert 'foo' not in text + + def test_not_in_text_single_long(self): + text = 'head ' * 50 + 'foo ' + 'tail ' * 20 + assert 'foo' not in text + + def test_not_in_text_single_long_term(self): + text = 'head ' * 50 + 'f'*70 + 'tail ' * 20 + assert 'f'*70 not in text + def test_attribute(): class Foo(object): diff --git a/testing/test_assertion.py b/testing/test_assertion.py index b4c74b0de..3cf76c19c 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -114,6 +114,11 @@ class TestAssert_reprcompare: expl = callequal(A(), '') assert not expl +def test_reprcompare_notin(): + detail = plugin.pytest_assertrepr_compare('not in', 'foo', 'aaafoobbb')[1:] + assert '- aaabbb' in detail + assert '+ aaafoobbb' in detail + @needsnewassert def test_pytest_assertrepr_compare_integration(testdir): testdir.makepyfile("""