From 8631c1f57a89b5ceaaf553f58b89a5820df9bf41 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Fri, 10 Dec 2010 01:03:26 +0000 Subject: [PATCH] Add "not in" to detailed explanations This simply uses difflib to compare the text without the offending string to the full text. Also ensures the summary line uses all space available. But the terminal width is still hardcoded. --- _pytest/assertion.py | 16 ++++++++++++++-- doc/example/assertion/failure_demo.py | 16 ++++++++++++++++ testing/test_assertion.py | 5 +++++ 3 files changed, 35 insertions(+), 2 deletions(-) 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("""