pytester: align prefixes

This is important for using another match_nickname, e.g. "re.match".

TODO:

- [ ] changelog
- [ ] test
This commit is contained in:
Daniel Hahler 2019-10-22 01:33:43 +02:00
parent 978c7ae1b7
commit 8ef4287bf0
3 changed files with 61 additions and 24 deletions

View File

@ -0,0 +1 @@
Align prefixes in output of pytester's ``LineMatcher``.

View File

@ -1344,7 +1344,6 @@ class LineMatcher:
pattern pattern
:param str match_nickname: the nickname for the match function that :param str match_nickname: the nickname for the match function that
will be logged to stdout when a match occurs will be logged to stdout when a match occurs
""" """
assert isinstance(lines2, Sequence) assert isinstance(lines2, Sequence)
lines2 = self._getlines(lines2) lines2 = self._getlines(lines2)
@ -1352,6 +1351,7 @@ class LineMatcher:
nextline = None nextline = None
extralines = [] extralines = []
__tracebackhide__ = True __tracebackhide__ = True
wnick = len(match_nickname) + 1
for line in lines2: for line in lines2:
nomatchprinted = False nomatchprinted = False
while lines1: while lines1:
@ -1361,17 +1361,21 @@ class LineMatcher:
break break
elif match_func(nextline, line): elif match_func(nextline, line):
self._log("%s:" % match_nickname, repr(line)) self._log("%s:" % match_nickname, repr(line))
self._log(" with:", repr(nextline)) self._log(
"{:>{width}}".format("with:", width=wnick), repr(nextline)
)
break break
else: else:
if not nomatchprinted: if not nomatchprinted:
self._log("nomatch:", repr(line)) self._log(
"{:>{width}}".format("nomatch:", width=wnick), repr(line)
)
nomatchprinted = True nomatchprinted = True
self._log(" and:", repr(nextline)) self._log("{:>{width}}".format("and:", width=wnick), repr(nextline))
extralines.append(nextline) extralines.append(nextline)
else: else:
self._log("remains unmatched: {!r}".format(line)) self._log("remains unmatched: {!r}".format(line))
pytest.fail(self._log_text) pytest.fail(self._log_text.lstrip())
def no_fnmatch_line(self, pat): def no_fnmatch_line(self, pat):
"""Ensure captured lines do not match the given pattern, using ``fnmatch.fnmatch``. """Ensure captured lines do not match the given pattern, using ``fnmatch.fnmatch``.
@ -1396,16 +1400,19 @@ class LineMatcher:
""" """
__tracebackhide__ = True __tracebackhide__ = True
nomatch_printed = False nomatch_printed = False
wnick = len(match_nickname) + 1
try: try:
for line in self.lines: for line in self.lines:
if match_func(line, pat): if match_func(line, pat):
self._log("%s:" % match_nickname, repr(pat)) self._log("%s:" % match_nickname, repr(pat))
self._log(" with:", repr(line)) self._log("{:>{width}}".format("with:", width=wnick), repr(line))
pytest.fail(self._log_text) pytest.fail(self._log_text.lstrip())
else: else:
if not nomatch_printed: if not nomatch_printed:
self._log("nomatch:", repr(pat)) self._log(
"{:>{width}}".format("nomatch:", width=wnick), repr(pat)
)
nomatch_printed = True nomatch_printed = True
self._log(" and:", repr(line)) self._log("{:>{width}}".format("and:", width=wnick), repr(line))
finally: finally:
self._log_output = [] self._log_output = []

View File

@ -457,16 +457,39 @@ def test_linematcher_with_nonlist():
assert lm._getlines(set()) == set() assert lm._getlines(set()) == set()
def test_linematcher_match_failure():
lm = LineMatcher(["foo", "foo", "bar"])
with pytest.raises(pytest.fail.Exception) as e:
lm.fnmatch_lines(["foo", "f*", "baz"])
assert e.value.msg.splitlines() == [
"exact match: 'foo'",
"fnmatch: 'f*'",
" with: 'foo'",
"nomatch: 'baz'",
" and: 'bar'",
"remains unmatched: 'baz'",
]
lm = LineMatcher(["foo", "foo", "bar"])
with pytest.raises(pytest.fail.Exception) as e:
lm.re_match_lines(["foo", "^f.*", "baz"])
assert e.value.msg.splitlines() == [
"exact match: 'foo'",
"re.match: '^f.*'",
" with: 'foo'",
" nomatch: 'baz'",
" and: 'bar'",
"remains unmatched: 'baz'",
]
@pytest.mark.parametrize("function", ["no_fnmatch_line", "no_re_match_line"]) @pytest.mark.parametrize("function", ["no_fnmatch_line", "no_re_match_line"])
def test_no_matching(function): def test_no_matching(function):
""""""
if function == "no_fnmatch_line": if function == "no_fnmatch_line":
match_func_name = "fnmatch"
good_pattern = "*.py OK*" good_pattern = "*.py OK*"
bad_pattern = "*X.py OK*" bad_pattern = "*X.py OK*"
else: else:
assert function == "no_re_match_line" assert function == "no_re_match_line"
match_func_name = "re.match"
good_pattern = r".*py OK" good_pattern = r".*py OK"
bad_pattern = r".*Xpy OK" bad_pattern = r".*Xpy OK"
@ -480,24 +503,30 @@ def test_no_matching(function):
] ]
) )
def check_failure_lines(lines):
expected = [
"nomatch: '{}'".format(good_pattern),
" and: 'cachedir: .pytest_cache'",
" and: 'collecting ... collected 1 item'",
" and: ''",
"{}: '{}'".format(match_func_name, good_pattern),
" with: 'show_fixtures_per_test.py OK'",
]
assert lines == expected
# check the function twice to ensure we don't accumulate the internal buffer # check the function twice to ensure we don't accumulate the internal buffer
for i in range(2): for i in range(2):
with pytest.raises(pytest.fail.Exception) as e: with pytest.raises(pytest.fail.Exception) as e:
func = getattr(lm, function) func = getattr(lm, function)
func(good_pattern) func(good_pattern)
obtained = str(e.value).splitlines() obtained = str(e.value).splitlines()
check_failure_lines(obtained) if function == "no_fnmatch_line":
assert obtained == [
"nomatch: '{}'".format(good_pattern),
" and: 'cachedir: .pytest_cache'",
" and: 'collecting ... collected 1 item'",
" and: ''",
"fnmatch: '{}'".format(good_pattern),
" with: 'show_fixtures_per_test.py OK'",
]
else:
assert obtained == [
"nomatch: '{}'".format(good_pattern),
" and: 'cachedir: .pytest_cache'",
" and: 'collecting ... collected 1 item'",
" and: ''",
"re.match: '{}'".format(good_pattern),
" with: 'show_fixtures_per_test.py OK'",
]
func = getattr(lm, function) func = getattr(lm, function)
func(bad_pattern) # bad pattern does not match any line: passes func(bad_pattern) # bad pattern does not match any line: passes