]>
Commit | Line | Data |
---|---|---|
1 | # -*- coding: utf-8 -*- | |
2 | # Copyright 2015 Google Inc. All Rights Reserved. | |
3 | # | |
4 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | # you may not use this file except in compliance with the License. | |
6 | # You may obtain a copy of the License at | |
7 | # | |
8 | # http://www.apache.org/licenses/LICENSE-2.0 | |
9 | # | |
10 | # Unless required by applicable law or agreed to in writing, software | |
11 | # distributed under the License is distributed on an "AS IS" BASIS, | |
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | # See the License for the specific language governing permissions and | |
14 | # limitations under the License. | |
15 | """Tests for yapf.style.""" | |
16 | ||
17 | import os | |
18 | import shutil | |
19 | import tempfile | |
20 | import textwrap | |
21 | import unittest | |
22 | ||
23 | from yapf.yapflib import style | |
24 | ||
25 | from yapftests import utils | |
26 | from yapftests import yapf_test_helper | |
27 | ||
28 | ||
29 | class UtilsTest(yapf_test_helper.YAPFTest): | |
30 | ||
31 | def testContinuationAlignStyleStringConverter(self): | |
32 | for cont_align_space in ('', 'space', '"space"', '\'space\''): | |
33 | self.assertEqual( | |
34 | style._ContinuationAlignStyleStringConverter(cont_align_space), | |
35 | 'SPACE') | |
36 | for cont_align_fixed in ('fixed', '"fixed"', '\'fixed\''): | |
37 | self.assertEqual( | |
38 | style._ContinuationAlignStyleStringConverter(cont_align_fixed), | |
39 | 'FIXED') | |
40 | for cont_align_valignright in ( | |
41 | 'valign-right', | |
42 | '"valign-right"', | |
43 | '\'valign-right\'', | |
44 | 'valign_right', | |
45 | '"valign_right"', | |
46 | '\'valign_right\'', | |
47 | ): | |
48 | self.assertEqual( | |
49 | style._ContinuationAlignStyleStringConverter(cont_align_valignright), | |
50 | 'VALIGN-RIGHT') | |
51 | with self.assertRaises(ValueError) as ctx: | |
52 | style._ContinuationAlignStyleStringConverter('blahblah') | |
53 | self.assertIn("unknown continuation align style: 'blahblah'", | |
54 | str(ctx.exception)) | |
55 | ||
56 | def testStringListConverter(self): | |
57 | self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) | |
58 | self.assertEqual(style._StringListConverter('foo,bar'), ['foo', 'bar']) | |
59 | self.assertEqual(style._StringListConverter(' foo'), ['foo']) | |
60 | self.assertEqual( | |
61 | style._StringListConverter('joe ,foo, bar'), ['joe', 'foo', 'bar']) | |
62 | ||
63 | def testBoolConverter(self): | |
64 | self.assertEqual(style._BoolConverter('true'), True) | |
65 | self.assertEqual(style._BoolConverter('1'), True) | |
66 | self.assertEqual(style._BoolConverter('false'), False) | |
67 | self.assertEqual(style._BoolConverter('0'), False) | |
68 | ||
69 | def testIntListConverter(self): | |
70 | self.assertEqual(style._IntListConverter('1, 2, 3'), [1, 2, 3]) | |
71 | self.assertEqual(style._IntListConverter('[ 1, 2, 3 ]'), [1, 2, 3]) | |
72 | self.assertEqual(style._IntListConverter('[ 1, 2, 3, ]'), [1, 2, 3]) | |
73 | ||
74 | def testIntOrIntListConverter(self): | |
75 | self.assertEqual(style._IntOrIntListConverter('10'), 10) | |
76 | self.assertEqual(style._IntOrIntListConverter('1, 2, 3'), [1, 2, 3]) | |
77 | ||
78 | ||
79 | def _LooksLikeGoogleStyle(cfg): | |
80 | return cfg['COLUMN_LIMIT'] == 80 and cfg['SPLIT_COMPLEX_COMPREHENSION'] | |
81 | ||
82 | ||
83 | def _LooksLikePEP8Style(cfg): | |
84 | return cfg['COLUMN_LIMIT'] == 79 | |
85 | ||
86 | ||
87 | def _LooksLikeFacebookStyle(cfg): | |
88 | return cfg['DEDENT_CLOSING_BRACKETS'] | |
89 | ||
90 | ||
91 | def _LooksLikeYapfStyle(cfg): | |
92 | return cfg['SPLIT_BEFORE_DOT'] | |
93 | ||
94 | ||
95 | class PredefinedStylesByNameTest(yapf_test_helper.YAPFTest): | |
96 | ||
97 | @classmethod | |
98 | def setUpClass(cls): # pylint: disable=g-missing-super-call | |
99 | style.SetGlobalStyle(style.CreatePEP8Style()) | |
100 | ||
101 | def testDefault(self): | |
102 | # default is PEP8 | |
103 | cfg = style.CreateStyleFromConfig(None) | |
104 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
105 | ||
106 | def testPEP8ByName(self): | |
107 | for pep8_name in ('PEP8', 'pep8', 'Pep8'): | |
108 | cfg = style.CreateStyleFromConfig(pep8_name) | |
109 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
110 | ||
111 | def testGoogleByName(self): | |
112 | for google_name in ('google', 'Google', 'GOOGLE'): | |
113 | cfg = style.CreateStyleFromConfig(google_name) | |
114 | self.assertTrue(_LooksLikeGoogleStyle(cfg)) | |
115 | ||
116 | def testYapfByName(self): | |
117 | for yapf_name in ('yapf', 'YAPF'): | |
118 | cfg = style.CreateStyleFromConfig(yapf_name) | |
119 | self.assertTrue(_LooksLikeYapfStyle(cfg)) | |
120 | ||
121 | def testFacebookByName(self): | |
122 | for fb_name in ('facebook', 'FACEBOOK', 'Facebook'): | |
123 | cfg = style.CreateStyleFromConfig(fb_name) | |
124 | self.assertTrue(_LooksLikeFacebookStyle(cfg)) | |
125 | ||
126 | ||
127 | class StyleFromFileTest(yapf_test_helper.YAPFTest): | |
128 | ||
129 | @classmethod | |
130 | def setUpClass(cls): # pylint: disable=g-missing-super-call | |
131 | cls.test_tmpdir = tempfile.mkdtemp() | |
132 | style.SetGlobalStyle(style.CreatePEP8Style()) | |
133 | ||
134 | @classmethod | |
135 | def tearDownClass(cls): # pylint: disable=g-missing-super-call | |
136 | shutil.rmtree(cls.test_tmpdir) | |
137 | ||
138 | def testDefaultBasedOnStyle(self): | |
139 | cfg = textwrap.dedent("""\ | |
140 | [style] | |
141 | continuation_indent_width = 20 | |
142 | """) | |
143 | with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: | |
144 | cfg = style.CreateStyleFromConfig(filepath) | |
145 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
146 | self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) | |
147 | ||
148 | def testDefaultBasedOnPEP8Style(self): | |
149 | cfg = textwrap.dedent("""\ | |
150 | [style] | |
151 | based_on_style = pep8 | |
152 | continuation_indent_width = 40 | |
153 | """) | |
154 | with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: | |
155 | cfg = style.CreateStyleFromConfig(filepath) | |
156 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
157 | self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) | |
158 | ||
159 | def testDefaultBasedOnGoogleStyle(self): | |
160 | cfg = textwrap.dedent("""\ | |
161 | [style] | |
162 | based_on_style = google | |
163 | continuation_indent_width = 20 | |
164 | """) | |
165 | with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: | |
166 | cfg = style.CreateStyleFromConfig(filepath) | |
167 | self.assertTrue(_LooksLikeGoogleStyle(cfg)) | |
168 | self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) | |
169 | ||
170 | def testDefaultBasedOnFacebookStyle(self): | |
171 | cfg = textwrap.dedent("""\ | |
172 | [style] | |
173 | based_on_style = facebook | |
174 | continuation_indent_width = 20 | |
175 | """) | |
176 | with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: | |
177 | cfg = style.CreateStyleFromConfig(filepath) | |
178 | self.assertTrue(_LooksLikeFacebookStyle(cfg)) | |
179 | self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) | |
180 | ||
181 | def testBoolOptionValue(self): | |
182 | cfg = textwrap.dedent("""\ | |
183 | [style] | |
184 | based_on_style = pep8 | |
185 | SPLIT_BEFORE_NAMED_ASSIGNS=False | |
186 | split_before_logical_operator = true | |
187 | """) | |
188 | with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: | |
189 | cfg = style.CreateStyleFromConfig(filepath) | |
190 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
191 | self.assertEqual(cfg['SPLIT_BEFORE_NAMED_ASSIGNS'], False) | |
192 | self.assertEqual(cfg['SPLIT_BEFORE_LOGICAL_OPERATOR'], True) | |
193 | ||
194 | def testStringListOptionValue(self): | |
195 | cfg = textwrap.dedent("""\ | |
196 | [style] | |
197 | based_on_style = pep8 | |
198 | I18N_FUNCTION_CALL = N_, V_, T_ | |
199 | """) | |
200 | with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: | |
201 | cfg = style.CreateStyleFromConfig(filepath) | |
202 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
203 | self.assertEqual(cfg['I18N_FUNCTION_CALL'], ['N_', 'V_', 'T_']) | |
204 | ||
205 | def testErrorNoStyleFile(self): | |
206 | with self.assertRaisesRegex(style.StyleConfigError, | |
207 | 'is not a valid style or file path'): | |
208 | style.CreateStyleFromConfig('/8822/xyznosuchfile') | |
209 | ||
210 | def testErrorNoStyleSection(self): | |
211 | cfg = textwrap.dedent("""\ | |
212 | [s] | |
213 | indent_width=2 | |
214 | """) | |
215 | with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: | |
216 | with self.assertRaisesRegex(style.StyleConfigError, | |
217 | 'Unable to find section'): | |
218 | style.CreateStyleFromConfig(filepath) | |
219 | ||
220 | def testErrorUnknownStyleOption(self): | |
221 | cfg = textwrap.dedent("""\ | |
222 | [style] | |
223 | indent_width=2 | |
224 | hummus=2 | |
225 | """) | |
226 | with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: | |
227 | with self.assertRaisesRegex(style.StyleConfigError, | |
228 | 'Unknown style option'): | |
229 | style.CreateStyleFromConfig(filepath) | |
230 | ||
231 | def testPyprojectTomlNoYapfSection(self): | |
232 | try: | |
233 | import tomli # noqa: F401 | |
234 | except ImportError: | |
235 | return | |
236 | ||
237 | filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') | |
238 | _ = open(filepath, 'w') | |
239 | with self.assertRaisesRegex(style.StyleConfigError, | |
240 | 'Unable to find section'): | |
241 | style.CreateStyleFromConfig(filepath) | |
242 | ||
243 | def testPyprojectTomlParseYapfSection(self): | |
244 | try: | |
245 | import tomli # noqa: F401 | |
246 | except ImportError: | |
247 | return | |
248 | ||
249 | cfg = textwrap.dedent("""\ | |
250 | [tool.yapf] | |
251 | based_on_style = "pep8" | |
252 | continuation_indent_width = 40 | |
253 | """) | |
254 | filepath = os.path.join(self.test_tmpdir, 'pyproject.toml') | |
255 | with open(filepath, 'w') as f: | |
256 | f.write(cfg) | |
257 | cfg = style.CreateStyleFromConfig(filepath) | |
258 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
259 | self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) | |
260 | ||
261 | ||
262 | class StyleFromDict(yapf_test_helper.YAPFTest): | |
263 | ||
264 | @classmethod | |
265 | def setUpClass(cls): # pylint: disable=g-missing-super-call | |
266 | style.SetGlobalStyle(style.CreatePEP8Style()) | |
267 | ||
268 | def testDefaultBasedOnStyle(self): | |
269 | config_dict = { | |
270 | 'based_on_style': 'pep8', | |
271 | 'indent_width': 2, | |
272 | 'blank_line_before_nested_class_or_def': True | |
273 | } | |
274 | cfg = style.CreateStyleFromConfig(config_dict) | |
275 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
276 | self.assertEqual(cfg['INDENT_WIDTH'], 2) | |
277 | ||
278 | def testDefaultBasedOnStyleBadDict(self): | |
279 | self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', | |
280 | style.CreateStyleFromConfig, | |
281 | {'based_on_styl': 'pep8'}) | |
282 | self.assertRaisesRegex(style.StyleConfigError, 'not a valid', | |
283 | style.CreateStyleFromConfig, | |
284 | {'INDENT_WIDTH': 'FOUR'}) | |
285 | ||
286 | ||
287 | class StyleFromCommandLine(yapf_test_helper.YAPFTest): | |
288 | ||
289 | @classmethod | |
290 | def setUpClass(cls): # pylint: disable=g-missing-super-call | |
291 | style.SetGlobalStyle(style.CreatePEP8Style()) | |
292 | ||
293 | def testDefaultBasedOnStyle(self): | |
294 | cfg = style.CreateStyleFromConfig( | |
295 | '{based_on_style: pep8,' | |
296 | ' indent_width: 2,' | |
297 | ' blank_line_before_nested_class_or_def: True}') | |
298 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
299 | self.assertEqual(cfg['INDENT_WIDTH'], 2) | |
300 | ||
301 | def testDefaultBasedOnStyleNotStrict(self): | |
302 | cfg = style.CreateStyleFromConfig( | |
303 | '{based_on_style : pep8,' | |
304 | ' indent_width=2' | |
305 | ' blank_line_before_nested_class_or_def:True}') | |
306 | self.assertTrue(_LooksLikePEP8Style(cfg)) | |
307 | self.assertEqual(cfg['INDENT_WIDTH'], 2) | |
308 | ||
309 | def testDefaultBasedOnExplicitlyUnicodeTypeString(self): | |
310 | cfg = style.CreateStyleFromConfig('{}') | |
311 | self.assertIsInstance(cfg, dict) | |
312 | ||
313 | def testDefaultBasedOnDetaultTypeString(self): | |
314 | cfg = style.CreateStyleFromConfig('{}') | |
315 | self.assertIsInstance(cfg, dict) | |
316 | ||
317 | def testDefaultBasedOnStyleBadString(self): | |
318 | self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option', | |
319 | style.CreateStyleFromConfig, '{based_on_styl: pep8}') | |
320 | self.assertRaisesRegex(style.StyleConfigError, 'not a valid', | |
321 | style.CreateStyleFromConfig, '{INDENT_WIDTH: FOUR}') | |
322 | self.assertRaisesRegex(style.StyleConfigError, 'Invalid style dict', | |
323 | style.CreateStyleFromConfig, '{based_on_style: pep8') | |
324 | ||
325 | ||
326 | class StyleHelp(yapf_test_helper.YAPFTest): | |
327 | ||
328 | def testHelpKeys(self): | |
329 | settings = sorted(style.Help()) | |
330 | expected = sorted(style._style) | |
331 | self.assertListEqual(settings, expected) | |
332 | ||
333 | ||
334 | if __name__ == '__main__': | |
335 | unittest.main() |