Skip to content

Commit 53f7584

Browse files
committed
test_handle_force_color_no_color
1 parent b100251 commit 53f7584

File tree

1 file changed

+141
-1
lines changed

1 file changed

+141
-1
lines changed

tests/lint/test_pylinter.py

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,35 @@
22
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
33
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
44

5+
from __future__ import annotations
6+
7+
import io
58
import os
9+
import sys
10+
import warnings
611
from pathlib import Path
712
from typing import Any, NoReturn
813
from unittest import mock
914
from unittest.mock import patch
1015

16+
import pytest
1117
from pytest import CaptureFixture
1218

13-
from pylint.lint.pylinter import PyLinter
19+
from pylint.lint.pylinter import (
20+
FORCE_COLOR,
21+
NO_COLOR,
22+
PY_COLORS,
23+
WARN_BOTH_COLOR_SET,
24+
PyLinter,
25+
_handle_force_color_no_color,
26+
)
27+
from pylint.reporters.text import ColorizedTextReporter, TextReporter
1428
from pylint.utils import FileState
1529

30+
COLORIZED_REPORTERS = "colorized_reporters"
31+
TEXT_REPORTERS = "text_reporters"
32+
STDOUT_TEXT = "stdout"
33+
1634

1735
def raise_exception(*args: Any, **kwargs: Any) -> NoReturn:
1836
raise ValueError
@@ -48,3 +66,125 @@ def test_crash_during_linting(
4866
assert len(files) == 1
4967
assert "pylint-crash-20" in str(files[0])
5068
assert any(m.symbol == "astroid-error" for m in linter.reporter.messages)
69+
70+
71+
def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
72+
if metafunc.function.__name__ != test_handle_force_color_no_color.__name__:
73+
return
74+
75+
if (
76+
TEXT_REPORTERS not in metafunc.fixturenames
77+
or COLORIZED_REPORTERS not in metafunc.fixturenames
78+
):
79+
warnings.warn(
80+
f"Missing fixture {TEXT_REPORTERS} or {COLORIZED_REPORTERS} in"
81+
f" {test_handle_force_color_no_color.function.__name__}??",
82+
stacklevel=2,
83+
)
84+
return
85+
86+
parameters = []
87+
88+
reporter_combinations = [
89+
("file", STDOUT_TEXT),
90+
("file",),
91+
(STDOUT_TEXT,),
92+
("",),
93+
]
94+
95+
for tr in list(reporter_combinations):
96+
for cr in list(reporter_combinations):
97+
tr = tuple(t for t in tr if t)
98+
cr = tuple(t for t in cr if t)
99+
100+
total_reporters = len(tr) + len(cr)
101+
unique_reporters = len(set(tr + cr))
102+
103+
if total_reporters == 0:
104+
continue
105+
106+
if unique_reporters != total_reporters:
107+
continue
108+
109+
parameters.append((tuple(tr), tuple(cr)))
110+
111+
metafunc.parametrize(
112+
f"{TEXT_REPORTERS}, {COLORIZED_REPORTERS}", parameters, ids=repr
113+
)
114+
115+
116+
@pytest.mark.parametrize("no_color", [True, False], ids=lambda no_color: f"{no_color=}")
117+
@pytest.mark.parametrize(
118+
"py_colors", [True, False], ids=lambda py_colors: f"{py_colors=}"
119+
)
120+
@pytest.mark.parametrize(
121+
"force_color", [True, False], ids=lambda force_color: f"{force_color=}"
122+
)
123+
def test_handle_force_color_no_color(
124+
monkeypatch: pytest.MonkeyPatch,
125+
recwarn: pytest.WarningsRecorder,
126+
no_color: bool,
127+
py_colors: bool,
128+
force_color: bool,
129+
text_reporters: tuple[str],
130+
colorized_reporters: tuple[str],
131+
) -> None:
132+
monkeypatch.setenv(NO_COLOR, "1" if no_color else "")
133+
monkeypatch.setenv(FORCE_COLOR, "1" if force_color else "")
134+
monkeypatch.setenv(PY_COLORS, "1" if py_colors else "")
135+
136+
force_color = force_color or py_colors
137+
138+
if STDOUT_TEXT in text_reporters or STDOUT_TEXT in colorized_reporters:
139+
monkeypatch.setattr(sys, STDOUT_TEXT, io.TextIOWrapper(io.BytesIO()))
140+
141+
reporters = []
142+
for reporter, group in (
143+
(TextReporter, text_reporters),
144+
(ColorizedTextReporter, colorized_reporters),
145+
):
146+
for name in group:
147+
if name == STDOUT_TEXT:
148+
reporters.append(reporter())
149+
if name == "file":
150+
reporters.append(reporter(io.TextIOWrapper(io.BytesIO())))
151+
152+
_handle_force_color_no_color(reporters)
153+
154+
if no_color and force_color:
155+
# Both NO_COLOR and FORCE_COLOR are set; expecting a warning.
156+
both_color_warning = [
157+
idx
158+
for idx, w in enumerate(recwarn.list)
159+
if WARN_BOTH_COLOR_SET in str(w.message)
160+
]
161+
assert len(both_color_warning) == 1
162+
recwarn.list.pop(both_color_warning[0])
163+
164+
if no_color:
165+
# No ColorizedTextReporter expected to be connected to stdout.
166+
assert all(
167+
not isinstance(rep, ColorizedTextReporter)
168+
for rep in reporters
169+
if rep.out.buffer is sys.stdout.buffer
170+
)
171+
172+
if STDOUT_TEXT in colorized_reporters:
173+
assert len(recwarn.list) == 1 # expect a warning for overriding stdout
174+
else:
175+
assert len(recwarn.list) == 0 # no warning expected
176+
elif force_color:
177+
# No TextReporter expected to be connected to stdout.
178+
# pylint: disable=unidiomatic-typecheck # Want explicit type check.
179+
assert all(
180+
type(rep) is not TextReporter
181+
for rep in reporters
182+
if rep.out.buffer is sys.stdout.buffer
183+
)
184+
185+
if STDOUT_TEXT in text_reporters:
186+
assert len(recwarn.list) == 1 # expect a warning for overriding stdout
187+
else:
188+
assert len(recwarn.list) == 0 # no warning expected
189+
else:
190+
assert len(recwarn.list) == 0 # no warning expected

0 commit comments

Comments
 (0)