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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
"""Tests for the BaseFormatter object."""
from __future__ import annotations
import argparse
import sys
from unittest import mock
import pytest
from flake8.formatting import _windows_color
from flake8.formatting import base
from flake8.violation import Violation
def options(**kwargs):
"""Create an argparse.Namespace instance."""
kwargs.setdefault("color", "auto")
kwargs.setdefault("output_file", None)
kwargs.setdefault("tee", False)
return argparse.Namespace(**kwargs)
@pytest.mark.parametrize("filename", [None, "out.txt"])
def test_start(filename):
"""Verify we open a new file in the start method."""
mock_open = mock.mock_open()
formatter = base.BaseFormatter(options(output_file=filename))
with mock.patch("flake8.formatting.base.open", mock_open):
formatter.start()
if filename is None:
assert mock_open.called is False
else:
mock_open.assert_called_once_with(filename, "a")
def test_stop():
"""Verify we close open file objects."""
filemock = mock.Mock()
formatter = base.BaseFormatter(options())
formatter.output_fd = filemock
formatter.stop()
filemock.close.assert_called_once_with()
assert formatter.output_fd is None
def test_format_needs_to_be_implemented():
"""Ensure BaseFormatter#format raises a NotImplementedError."""
formatter = base.BaseFormatter(options())
with pytest.raises(NotImplementedError):
formatter.format(
Violation("A000", "file.py", 1, 1, "error text", None)
)
def test_show_source_returns_nothing_when_not_showing_source():
"""Ensure we return nothing when users want nothing."""
formatter = base.BaseFormatter(options(show_source=False))
assert (
formatter.show_source(
Violation("A000", "file.py", 1, 1, "error text", "line")
)
== ""
)
def test_show_source_returns_nothing_when_there_is_source():
"""Ensure we return nothing when there is no line."""
formatter = base.BaseFormatter(options(show_source=True))
assert (
formatter.show_source(
Violation("A000", "file.py", 1, 1, "error text", None)
)
== ""
)
@pytest.mark.parametrize(
("line1", "line2", "column"),
[
(
"x=1\n",
" ^",
2,
),
(
" x=(1\n +2)\n",
" ^",
5,
),
(
"\tx\t=\ty\n",
"\t \t \t^",
6,
),
],
)
def test_show_source_updates_physical_line_appropriately(line1, line2, column):
"""Ensure the error column is appropriately indicated."""
formatter = base.BaseFormatter(options(show_source=True))
error = Violation("A000", "file.py", 1, column, "error", line1)
output = formatter.show_source(error)
assert output == line1 + line2
@pytest.mark.parametrize("tee", [False, True])
def test_write_uses_an_output_file(tee, capsys):
"""Verify that we use the output file when it's present."""
line = "Something to write"
source = "source"
filemock = mock.Mock()
formatter = base.BaseFormatter(options(tee=tee))
formatter.output_fd = filemock
formatter.write(line, source)
if tee:
assert capsys.readouterr().out == f"{line}\n{source}\n"
else:
assert capsys.readouterr().out == ""
assert filemock.write.called is True
assert filemock.write.call_count == 2
assert filemock.write.mock_calls == [
mock.call(line + formatter.newline),
mock.call(source + formatter.newline),
]
def test_write_produces_stdout(capsys):
"""Verify that we write to stdout without an output file."""
line = "Something to write"
source = "source"
formatter = base.BaseFormatter(options())
formatter.write(line, source)
assert capsys.readouterr().out == f"{line}\n{source}\n"
def test_color_always_is_true():
"""Verify that color='always' sets it to True."""
formatter = base.BaseFormatter(options(color="always"))
assert formatter.color is True
def _mock_isatty(val):
attrs = {"isatty.return_value": val}
return mock.patch.object(sys, "stdout", **attrs)
def _mock_windows_color(val):
return mock.patch.object(_windows_color, "terminal_supports_color", val)
def test_color_auto_is_true_for_tty():
"""Verify that color='auto' sets it to True for a tty."""
with _mock_isatty(True), _mock_windows_color(True):
formatter = base.BaseFormatter(options(color="auto"))
assert formatter.color is True
def test_color_auto_is_false_without_tty():
"""Verify that color='auto' sets it to False without a tty."""
with _mock_isatty(False), _mock_windows_color(True):
formatter = base.BaseFormatter(options(color="auto"))
assert formatter.color is False
def test_color_auto_is_false_if_not_supported_on_windows():
"""Verify that color='auto' is False if not supported on windows."""
with _mock_isatty(True), _mock_windows_color(False):
formatter = base.BaseFormatter(options(color="auto"))
assert formatter.color is False
def test_color_never_is_false():
"""Verify that color='never' sets it to False despite a tty."""
with _mock_isatty(True), _mock_windows_color(True):
formatter = base.BaseFormatter(options(color="never"))
assert formatter.color is False
class AfterInitFormatter(base.BaseFormatter):
"""Subclass for testing after_init."""
def after_init(self):
"""Define method to verify operation."""
self.post_initialized = True
def test_after_init_is_always_called():
"""Verify after_init is called."""
formatter = AfterInitFormatter(options())
assert formatter.post_initialized is True
class FormatFormatter(base.BaseFormatter):
"""Subclass for testing format."""
def format(self, error):
"""Define method to verify operation."""
return repr(error)
def test_handle_formats_the_error():
"""Verify that a formatter will call format from handle."""
formatter = FormatFormatter(options(show_source=False))
filemock = formatter.output_fd = mock.Mock()
error = Violation(
code="A001",
filename="example.py",
line_number=1,
column_number=1,
text="Fake error",
physical_line="a = 1",
)
formatter.handle(error)
filemock.write.assert_called_once_with(repr(error) + "\n")
|