forked from pantsbuild/pants
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rules_integration_test.py
161 lines (145 loc) · 7.19 KB
/
rules_integration_test.py
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
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
from typing import List, Optional, Sequence, Tuple
from pants.backend.python.lint.black.rules import BlackFieldSet, BlackRequest
from pants.backend.python.lint.black.rules import rules as black_rules
from pants.backend.python.target_types import PythonLibrary
from pants.core.goals.fmt import FmtResult
from pants.core.goals.lint import LintResult, LintResults
from pants.core.util_rules.source_files import SourceFiles, SourceFilesRequest
from pants.engine.addresses import Address
from pants.engine.fs import CreateDigest, Digest, FileContent
from pants.engine.rules import QueryRule
from pants.engine.target import Target
from pants.option.options_bootstrapper import OptionsBootstrapper
from pants.testutil.external_tool_test_base import ExternalToolTestBase
from pants.testutil.option_util import create_options_bootstrapper
class BlackIntegrationTest(ExternalToolTestBase):
good_source = FileContent(path="good.py", content=b'animal = "Koala"\n')
bad_source = FileContent(path="bad.py", content=b'name= "Anakin"\n')
fixed_bad_source = FileContent(path="bad.py", content=b'name = "Anakin"\n')
# Note the single quotes, which Black does not like by default. To get Black to pass, it will
# need to successfully read our config/CLI args.
needs_config_source = FileContent(path="needs_config.py", content=b"animal = 'Koala'\n")
@classmethod
def rules(cls):
return (
*super().rules(),
*black_rules(),
QueryRule(LintResults, (BlackRequest, OptionsBootstrapper)),
QueryRule(FmtResult, (BlackRequest, OptionsBootstrapper)),
QueryRule(SourceFiles, (SourceFilesRequest, OptionsBootstrapper)),
)
def make_target(self, source_files: List[FileContent]) -> Target:
for source_file in source_files:
self.create_file(f"{source_file.path}", source_file.content.decode())
return PythonLibrary({}, address=Address.parse(":target"))
def run_black(
self,
targets: List[Target],
*,
config: Optional[str] = None,
passthrough_args: Optional[str] = None,
skip: bool = False,
) -> Tuple[Sequence[LintResult], FmtResult]:
args = ["--backend-packages=pants.backend.python.lint.black"]
if config is not None:
self.create_file(relpath="pyproject.toml", contents=config)
args.append("--black-config=pyproject.toml")
if passthrough_args:
args.append(f"--black-args='{passthrough_args}'")
if skip:
args.append("--black-skip")
options_bootstrapper = create_options_bootstrapper(args=args)
field_sets = [BlackFieldSet.create(tgt) for tgt in targets]
lint_results = self.request_product(
LintResults, [BlackRequest(field_sets), options_bootstrapper]
)
input_sources = self.request_product(
SourceFiles,
[
SourceFilesRequest(field_set.sources for field_set in field_sets),
options_bootstrapper,
],
)
fmt_result = self.request_product(
FmtResult,
[
BlackRequest(field_sets, prior_formatter_result=input_sources.snapshot),
options_bootstrapper,
],
)
return lint_results.results, fmt_result
def get_digest(self, source_files: List[FileContent]) -> Digest:
return self.request_product(Digest, [CreateDigest(source_files)])
def test_passing_source(self) -> None:
target = self.make_target([self.good_source])
lint_results, fmt_result = self.run_black([target])
assert len(lint_results) == 1
assert lint_results[0].exit_code == 0
assert "1 file would be left unchanged" in lint_results[0].stderr
assert "1 file left unchanged" in fmt_result.stderr
assert fmt_result.output == self.get_digest([self.good_source])
assert fmt_result.did_change is False
def test_failing_source(self) -> None:
target = self.make_target([self.bad_source])
lint_results, fmt_result = self.run_black([target])
assert len(lint_results) == 1
assert lint_results[0].exit_code == 1
assert "1 file would be reformatted" in lint_results[0].stderr
assert "1 file reformatted" in fmt_result.stderr
assert fmt_result.output == self.get_digest([self.fixed_bad_source])
assert fmt_result.did_change is True
def test_mixed_sources(self) -> None:
target = self.make_target([self.good_source, self.bad_source])
lint_results, fmt_result = self.run_black([target])
assert len(lint_results) == 1
assert lint_results[0].exit_code == 1
assert (
"1 file would be reformatted, 1 file would be left unchanged" in lint_results[0].stderr
)
assert "1 file reformatted, 1 file left unchanged", fmt_result.stderr
assert fmt_result.output == self.get_digest([self.good_source, self.fixed_bad_source])
assert fmt_result.did_change is True
def test_multiple_targets(self) -> None:
targets = [
self.make_target([self.good_source]),
self.make_target([self.bad_source]),
]
lint_results, fmt_result = self.run_black(targets)
assert len(lint_results) == 1
assert lint_results[0].exit_code == 1
assert (
"1 file would be reformatted, 1 file would be left unchanged" in lint_results[0].stderr
)
assert "1 file reformatted, 1 file left unchanged" in fmt_result.stderr
assert fmt_result.output == self.get_digest([self.good_source, self.fixed_bad_source])
assert fmt_result.did_change is True
def test_respects_config_file(self) -> None:
target = self.make_target([self.needs_config_source])
lint_results, fmt_result = self.run_black(
[target], config="[tool.black]\nskip-string-normalization = 'true'\n"
)
assert len(lint_results) == 1
assert lint_results[0].exit_code == 0
assert "1 file would be left unchanged" in lint_results[0].stderr
assert "1 file left unchanged" in fmt_result.stderr
assert fmt_result.output == self.get_digest([self.needs_config_source])
assert fmt_result.did_change is False
def test_respects_passthrough_args(self) -> None:
target = self.make_target([self.needs_config_source])
lint_results, fmt_result = self.run_black(
[target], passthrough_args="--skip-string-normalization",
)
assert len(lint_results) == 1
assert lint_results[0].exit_code == 0
assert "1 file would be left unchanged" in lint_results[0].stderr
assert "1 file left unchanged" in fmt_result.stderr
assert fmt_result.output == self.get_digest([self.needs_config_source])
assert fmt_result.did_change is False
def test_skip(self) -> None:
target = self.make_target([self.bad_source])
lint_results, fmt_result = self.run_black([target], skip=True)
assert not lint_results
assert fmt_result.skipped is True
assert fmt_result.did_change is False