summaryrefslogtreecommitdiff
path: root/tests/config/test_functional_config_loading.py
blob: 5d3696c2fc2edf0155ea98e6fdae80a062892976 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE

"""
This launch the configuration functional tests. This permit to test configuration
files by providing a file with the appropriate extension in the ``tests/config/functional``
directory.

Let's say you have a regression_list_crash.toml file to test. Then if there is an error in the conf,
add ``regression_list_crash.out`` alongside your file with the expected output of pylint in it. Use
``{relpath}`` and ``{abspath}`` for the path of the file. The exit code will have to be 2 (error)
if this file exists.

You must also define a ``regression_list_crash.result.json`` if you want to check the parsed configuration.
This file will be loaded as a dict and will override the default value of the default pylint
configuration. If you need to append or remove a value use the special key ``"functional_append"``
and ``"functional_remove":``. Check the existing code for example.
"""

# pylint: disable=redefined-outer-name

from pathlib import Path
from typing import Any, Dict

import pytest
from _pytest.capture import CaptureFixture

from pylint.testutils.configuration_test import (
    get_expected_configuration,
    get_expected_output,
    run_using_a_configuration_file,
)

HERE = Path(__file__).parent
FUNCTIONAL_DIR = HERE / "functional"
# We use string then recast to path so we can use -k in pytest otherwise
# we get 'configuration_path0' as a test name. Relative to the functional
# directory because otherwise the string is very lengthy
CONFIGURATION_PATHS = [
    str(path.relative_to(FUNCTIONAL_DIR))
    for ext in ("toml", "ini", "cfg")
    for path in FUNCTIONAL_DIR.rglob(f"*.{ext}")
]
FILE_TO_LINT = str(HERE / "file_to_lint.py")


@pytest.fixture()
def default_configuration(tmp_path: Path) -> Dict[str, Any]:
    empty_pylintrc = tmp_path / "pylintrc"
    empty_pylintrc.write_text("")
    mock_exit, _, runner = run_using_a_configuration_file(
        str(empty_pylintrc), FILE_TO_LINT
    )
    mock_exit.assert_called_once_with(0)
    return runner.linter.config.__dict__


@pytest.mark.parametrize("configuration_path", CONFIGURATION_PATHS)
def test_functional_config_loading(
    configuration_path: str,
    default_configuration: Dict[str, Any],
    capsys: CaptureFixture,
):
    """Functional tests for configurations."""
    configuration_path = str(FUNCTIONAL_DIR / configuration_path)
    msg = f"Wrong result with configuration {configuration_path}"
    expected_code, expected_output = get_expected_output(configuration_path)
    expected_loaded_configuration = get_expected_configuration(
        configuration_path, default_configuration
    )
    mock_exit, _, runner = run_using_a_configuration_file(
        configuration_path, FILE_TO_LINT
    )
    mock_exit.assert_called_once_with(expected_code)
    out, err = capsys.readouterr()
    # rstrip() applied so we can have a final newline in the expected test file
    assert expected_output.rstrip() == out.rstrip(), msg
    assert expected_loaded_configuration == runner.linter.config.__dict__
    assert not err, msg