Flexible matching of text. This is a convenience class to test large texts like the output of commands. The constructor takes a list of lines without their trailing newlines, i.e. ``text.splitlines()``.
| 1523 | |
| 1524 | |
| 1525 | class LineMatcher: |
| 1526 | """Flexible matching of text. |
| 1527 | |
| 1528 | This is a convenience class to test large texts like the output of |
| 1529 | commands. |
| 1530 | |
| 1531 | The constructor takes a list of lines without their trailing newlines, i.e. |
| 1532 | ``text.splitlines()``. |
| 1533 | """ |
| 1534 | |
| 1535 | def __init__(self, lines: List[str]) -> None: |
| 1536 | self.lines = lines |
| 1537 | self._log_output: List[str] = [] |
| 1538 | |
| 1539 | def __str__(self) -> str: |
| 1540 | """Return the entire original text. |
| 1541 | |
| 1542 | .. versionadded:: 6.2 |
| 1543 | You can use :meth:`str` in older versions. |
| 1544 | """ |
| 1545 | return "\n".join(self.lines) |
| 1546 | |
| 1547 | def _getlines(self, lines2: Union[str, Sequence[str], Source]) -> Sequence[str]: |
| 1548 | if isinstance(lines2, str): |
| 1549 | lines2 = Source(lines2) |
| 1550 | if isinstance(lines2, Source): |
| 1551 | lines2 = lines2.strip().lines |
| 1552 | return lines2 |
| 1553 | |
| 1554 | def fnmatch_lines_random(self, lines2: Sequence[str]) -> None: |
| 1555 | """Check lines exist in the output in any order (using :func:`python:fnmatch.fnmatch`).""" |
| 1556 | __tracebackhide__ = True |
| 1557 | self._match_lines_random(lines2, fnmatch) |
| 1558 | |
| 1559 | def re_match_lines_random(self, lines2: Sequence[str]) -> None: |
| 1560 | """Check lines exist in the output in any order (using :func:`python:re.match`).""" |
| 1561 | __tracebackhide__ = True |
| 1562 | self._match_lines_random(lines2, lambda name, pat: bool(re.match(pat, name))) |
| 1563 | |
| 1564 | def _match_lines_random( |
| 1565 | self, lines2: Sequence[str], match_func: Callable[[str, str], bool] |
| 1566 | ) -> None: |
| 1567 | __tracebackhide__ = True |
| 1568 | lines2 = self._getlines(lines2) |
| 1569 | for line in lines2: |
| 1570 | for x in self.lines: |
| 1571 | if line == x or match_func(x, line): |
| 1572 | self._log("matched: ", repr(line)) |
| 1573 | break |
| 1574 | else: |
| 1575 | msg = "line %r not found in output" % line |
| 1576 | self._log(msg) |
| 1577 | self._fail(msg) |
| 1578 | |
| 1579 | def get_lines_after(self, fnline: str) -> Sequence[str]: |
| 1580 | """Return all lines following the given line in the text. |
| 1581 | |
| 1582 | The given line can contain glob wildcards. |
no outgoing calls