|
3 | 3 | # Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt |
4 | 4 |
|
5 | 5 | from contextlib import redirect_stdout |
6 | | -from io import StringIO |
| 6 | +from io import BytesIO, StringIO |
7 | 7 | from pathlib import Path |
8 | 8 |
|
| 9 | +import astroid |
9 | 10 | import pytest |
10 | 11 | from _pytest.capture import CaptureFixture |
11 | 12 |
|
12 | 13 | from pylint.checkers import symilar |
| 14 | +from pylint.checkers.symilar import LineSet, LineSetStartCouple, Symilar |
13 | 15 | from pylint.lint import PyLinter |
| 16 | +from pylint.reporters.ureports.nodes import Section, Table |
14 | 17 | from pylint.testutils import GenericTestReporter as Reporter |
| 18 | +from pylint.utils import LinterStats |
15 | 19 |
|
16 | 20 | INPUT = Path(__file__).parent / ".." / "input" |
17 | 21 | SIMILAR1 = str(INPUT / "similar1") |
@@ -472,6 +476,75 @@ def test_bad_short_form_option(capsys: CaptureFixture) -> None: |
472 | 476 | assert "unrecognized arguments: -j=0" in err |
473 | 477 |
|
474 | 478 |
|
| 479 | +def test_line_set_start_couple_eq_non_couple() -> None: |
| 480 | + """``LineSetStartCouple.__eq__`` returns ``NotImplemented`` against a |
| 481 | + non-LineSetStartCouple so Python falls back to reflected comparison. |
| 482 | + """ |
| 483 | + couple = LineSetStartCouple(symilar.Index(0), symilar.Index(1)) |
| 484 | + assert couple != object() |
| 485 | + # pylint: disable-next=unnecessary-dunder-call |
| 486 | + assert couple.__eq__(object()) is NotImplemented |
| 487 | + |
| 488 | + |
| 489 | +def test_line_set_dunder_methods() -> None: |
| 490 | + """Cover LineSet ``__str__``, ``__getitem__`` and non-LineSet ``__eq__``.""" |
| 491 | + lines = ["a = 1\n", "b = 2\n", "c = 3\n"] |
| 492 | + lineset = LineSet("fake.py", lines) |
| 493 | + assert str(lineset) == "<Lineset for fake.py>" |
| 494 | + assert lineset[0].text == "a = 1" |
| 495 | + assert (lineset == "not a lineset") is False |
| 496 | + |
| 497 | + |
| 498 | +def test_append_stream_binary_requires_encoding() -> None: |
| 499 | + """``append_stream`` raises ValueError when a binary stream is passed |
| 500 | + without an encoding. |
| 501 | + """ |
| 502 | + runner = Symilar() |
| 503 | + with pytest.raises(ValueError): |
| 504 | + runner.append_stream("bin.py", BytesIO(b"a = 1\n")) |
| 505 | + |
| 506 | + |
| 507 | +def test_report_similarities_builds_table() -> None: |
| 508 | + """``report_similarities`` appends a stats table to the given section.""" |
| 509 | + stats = LinterStats() |
| 510 | + stats.reset_duplicated_lines() |
| 511 | + section = Section() |
| 512 | + symilar.report_similarities(section, stats, None) |
| 513 | + assert len(section.children) == 1 |
| 514 | + assert isinstance(section.children[0], Table) |
| 515 | + |
| 516 | + |
| 517 | +def test_process_module_warns_when_current_name_is_none(tmp_path: Path) -> None: |
| 518 | + """``SimilaritiesChecker.process_module`` warns when |
| 519 | + ``linter.current_name`` is None (the deprecated state). |
| 520 | + """ |
| 521 | + linter = PyLinter(reporter=Reporter()) |
| 522 | + linter.register_checker(symilar.SimilaritiesChecker(linter)) |
| 523 | + checker = symilar.SimilaritiesChecker(linter) |
| 524 | + linter.current_name = None # type: ignore[assignment] |
| 525 | + module_file = tmp_path / "m.py" |
| 526 | + module_file.write_text("a = 1\n") |
| 527 | + |
| 528 | + module = astroid.parse(module_file.read_text(), module_name="m") |
| 529 | + module.file = str(module_file) |
| 530 | + module.file_bytes = module_file.read_bytes() |
| 531 | + with pytest.warns(DeprecationWarning, match="current_name attribute"): |
| 532 | + checker.process_module(module) |
| 533 | + |
| 534 | + |
| 535 | +def test_append_stream_unicode_error_yields_empty_lineset(tmp_path: Path) -> None: |
| 536 | + """``append_stream`` swallows ``UnicodeDecodeError`` and treats the file |
| 537 | + as empty rather than crashing. |
| 538 | + """ |
| 539 | + bad_file = tmp_path / "bad.py" |
| 540 | + bad_file.write_bytes(b"\xff\xfe\xfa not valid utf-8\n") |
| 541 | + runner = Symilar() |
| 542 | + with bad_file.open("rb") as stream: |
| 543 | + runner.append_stream(str(bad_file), stream, encoding="utf-8") |
| 544 | + assert len(runner.linesets) == 1 |
| 545 | + assert runner.linesets[0].stripped_lines == [] |
| 546 | + |
| 547 | + |
475 | 548 | def test_hash_bucket_product_limit_fallback( |
476 | 549 | monkeypatch: pytest.MonkeyPatch, tmp_path: Path |
477 | 550 | ) -> None: |
|
0 commit comments