blob: c2e87cd2f0b43a3554c283ef4afb70749400a9ad [file] [log] [blame]
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
"""Unittest for the BaseChecker class."""
import pytest
from pylint.checkers import BaseChecker
from pylint.checkers.imports import ImportsChecker
from pylint.checkers.typecheck import TypeChecker
from pylint.exceptions import InvalidMessageError
from pylint.extensions.broad_try_clause import BroadTryClauseChecker
from pylint.extensions.while_used import WhileChecker
from pylint.lint.pylinter import PyLinter
class OtherBasicChecker(BaseChecker):
def __init__(self) -> None:
super().__init__(PyLinter())
name = "basic"
msgs = {
"W0001": (
"Basic checker has an example.",
"basic-checker-example",
"Used nowhere and serves no purpose.",
)
}
class MissingFieldsChecker(BaseChecker):
name = "basic"
msgs = {"W0001": ("msg-name",)} # type: ignore[dict-item]
class LessBasicChecker(OtherBasicChecker):
options = (
(
"example-args",
{
"default": 42,
"type": "int",
"metavar": "<int>",
"help": "Example of integer argument for the checker.",
},
),
)
class DifferentBasicChecker(BaseChecker):
def __init__(self) -> None:
super().__init__(PyLinter())
name = "a-different-checker"
msgs = {
"W0002": (
"Blah blah example.",
"blah-blah-example",
"I only exist to be different to OtherBasicChecker :(",
)
}
class MessageWithOptionsChecker(BaseChecker):
name = "message-with-options-checker"
msgs = {
"W0003": (
"Just a message with pre-defined options %s()",
"message-with-options",
"Message with options dict to test consistent hashing.",
{"old_names": [("W1003", "old-message-with-options")], "shared": True},
),
}
def test_base_checker_doc() -> None:
basic = OtherBasicChecker()
expected_beginning = """\
Basic checker
~~~~~~~~~~~~~
Verbatim name of the checker is ``basic``.
"""
expected_middle = """\
Basic checker Options
^^^^^^^^^^^^^^^^^^^^^
:example-args:
Example of integer argument for the checker.
Default: ``42``
"""
expected_end = """\
Basic checker Messages
^^^^^^^^^^^^^^^^^^^^^^
:basic-checker-example (W0001): *Basic checker has an example.*
Used nowhere and serves no purpose.
"""
assert str(basic) == expected_beginning + expected_end
assert repr(basic) == "Checker 'basic' (responsible for 'W0001')"
less_basic = LessBasicChecker()
assert str(less_basic) == expected_beginning + expected_middle + expected_end
assert repr(less_basic) == repr(basic)
def test_base_checker_ordering() -> None:
"""Test ordering of checkers based on their __gt__ method."""
linter = PyLinter()
imports_builtin = ImportsChecker(linter)
typecheck_builtin = TypeChecker(linter)
basic_1_ext = OtherBasicChecker()
basic_2_ext = LessBasicChecker()
basic_3_ext = DifferentBasicChecker()
while_used_ext = WhileChecker(linter)
broad_try_clause_ext = BroadTryClauseChecker(linter)
list_of_checkers = [
1,
basic_1_ext,
basic_2_ext,
basic_3_ext,
typecheck_builtin,
broad_try_clause_ext,
imports_builtin,
while_used_ext,
linter,
]
assert sorted(list_of_checkers) == [ # type: ignore[type-var]
linter,
imports_builtin,
typecheck_builtin,
basic_3_ext,
basic_1_ext,
basic_2_ext,
broad_try_clause_ext,
while_used_ext,
1,
]
# main checker is always smaller
assert linter < basic_1_ext
assert linter < while_used_ext
assert linter < imports_builtin
assert basic_2_ext > linter
assert while_used_ext > linter
assert imports_builtin > linter
# builtin are smaller than extension (even when not alphabetically)
assert imports_builtin < while_used_ext
assert imports_builtin < broad_try_clause_ext
assert while_used_ext > imports_builtin
assert broad_try_clause_ext > imports_builtin
# alphabetical order for builtin
assert imports_builtin < typecheck_builtin
assert typecheck_builtin > imports_builtin
# alphabetical order for extension
assert typecheck_builtin < while_used_ext
assert while_used_ext > typecheck_builtin
assert basic_1_ext > basic_3_ext
assert basic_2_ext > basic_3_ext
assert basic_1_ext == basic_2_ext
def test_base_checker_invalid_message() -> None:
linter = PyLinter()
with pytest.raises(InvalidMessageError):
linter.register_checker(MissingFieldsChecker(linter))
def test_base_checker_consistent_hash() -> None:
linter = PyLinter()
checker = MessageWithOptionsChecker(linter)
some_set = {checker}
original_hash = hash(checker)
assert checker in some_set
for msgid, msg in checker.msgs.items():
checker.create_message_definition_from_tuple(msgid, msg)
assert hash(checker) == original_hash
assert checker in some_set