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 17import shutil 18import tempfile 19import textwrap 20import unittest 21 22from yapf.yapflib import style 23 24from yapftests import utils 25 26 27class UtilsTest(unittest.TestCase): 28 29 def testContinuationAlignStyleStringConverter(self): 30 self.assertEqual(style._ContinuationAlignStyleStringConverter(''), 'SPACE') 31 self.assertEqual( 32 style._ContinuationAlignStyleStringConverter('space'), 'SPACE') 33 self.assertEqual( 34 style._ContinuationAlignStyleStringConverter('fixed'), 'FIXED') 35 self.assertEqual( 36 style._ContinuationAlignStyleStringConverter('valign-right'), 37 'VALIGN-RIGHT') 38 with self.assertRaises(ValueError) as ctx: 39 style._ContinuationAlignStyleStringConverter('blahblah') 40 self.assertIn("unknown continuation align style: 'blahblah'", 41 str(ctx.exception)) 42 43 def testStringListConverter(self): 44 self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) 45 self.assertEqual(style._StringListConverter('foo,bar'), ['foo', 'bar']) 46 self.assertEqual(style._StringListConverter(' foo'), ['foo']) 47 self.assertEqual( 48 style._StringListConverter('joe ,foo, bar'), ['joe', 'foo', 'bar']) 49 50 def testBoolConverter(self): 51 self.assertEqual(style._BoolConverter('true'), True) 52 self.assertEqual(style._BoolConverter('1'), True) 53 self.assertEqual(style._BoolConverter('false'), False) 54 self.assertEqual(style._BoolConverter('0'), False) 55 56 57def _LooksLikeChromiumStyle(cfg): 58 return (cfg['INDENT_WIDTH'] == 2 and 59 cfg['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF']) 60 61 62def _LooksLikeGoogleStyle(cfg): 63 return (cfg['INDENT_WIDTH'] == 4 and 64 cfg['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF']) 65 66 67def _LooksLikePEP8Style(cfg): 68 return (cfg['INDENT_WIDTH'] == 4 and 69 not cfg['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF']) 70 71 72def _LooksLikeFacebookStyle(cfg): 73 return cfg['INDENT_WIDTH'] == 4 and cfg['DEDENT_CLOSING_BRACKETS'] 74 75 76class PredefinedStylesByNameTest(unittest.TestCase): 77 78 @classmethod 79 def setUpClass(cls): 80 style.SetGlobalStyle(style.CreatePEP8Style()) 81 82 def testDefault(self): 83 # default is PEP8 84 cfg = style.CreateStyleFromConfig(None) 85 self.assertTrue(_LooksLikePEP8Style(cfg)) 86 87 def testPEP8ByName(self): 88 for pep8_name in ('PEP8', 'pep8', 'Pep8'): 89 cfg = style.CreateStyleFromConfig(pep8_name) 90 self.assertTrue(_LooksLikePEP8Style(cfg)) 91 92 def testGoogleByName(self): 93 for google_name in ('google', 'Google', 'GOOGLE'): 94 cfg = style.CreateStyleFromConfig(google_name) 95 self.assertTrue(_LooksLikeGoogleStyle(cfg)) 96 97 def testChromiumByName(self): 98 for chromium_name in ('chromium', 'Chromium', 'CHROMIUM'): 99 cfg = style.CreateStyleFromConfig(chromium_name) 100 self.assertTrue(_LooksLikeChromiumStyle(cfg)) 101 102 def testFacebookByName(self): 103 for fb_name in ('facebook', 'FACEBOOK', 'Facebook'): 104 cfg = style.CreateStyleFromConfig(fb_name) 105 self.assertTrue(_LooksLikeFacebookStyle(cfg)) 106 107 108class StyleFromFileTest(unittest.TestCase): 109 110 @classmethod 111 def setUpClass(cls): 112 cls.test_tmpdir = tempfile.mkdtemp() 113 style.SetGlobalStyle(style.CreatePEP8Style()) 114 115 @classmethod 116 def tearDownClass(cls): 117 shutil.rmtree(cls.test_tmpdir) 118 119 def testDefaultBasedOnStyle(self): 120 cfg = textwrap.dedent(u'''\ 121 [style] 122 continuation_indent_width = 20 123 ''') 124 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 125 cfg = style.CreateStyleFromConfig(filepath) 126 self.assertTrue(_LooksLikePEP8Style(cfg)) 127 self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) 128 129 def testDefaultBasedOnPEP8Style(self): 130 cfg = textwrap.dedent(u'''\ 131 [style] 132 based_on_style = pep8 133 continuation_indent_width = 40 134 ''') 135 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 136 cfg = style.CreateStyleFromConfig(filepath) 137 self.assertTrue(_LooksLikePEP8Style(cfg)) 138 self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 40) 139 140 def testDefaultBasedOnChromiumStyle(self): 141 cfg = textwrap.dedent(u'''\ 142 [style] 143 based_on_style = chromium 144 continuation_indent_width = 30 145 ''') 146 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 147 cfg = style.CreateStyleFromConfig(filepath) 148 self.assertTrue(_LooksLikeChromiumStyle(cfg)) 149 self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 30) 150 151 def testDefaultBasedOnGoogleStyle(self): 152 cfg = textwrap.dedent(u'''\ 153 [style] 154 based_on_style = google 155 continuation_indent_width = 20 156 ''') 157 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 158 cfg = style.CreateStyleFromConfig(filepath) 159 self.assertTrue(_LooksLikeGoogleStyle(cfg)) 160 self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) 161 162 def testDefaultBasedOnFacebookStyle(self): 163 cfg = textwrap.dedent(u'''\ 164 [style] 165 based_on_style = facebook 166 continuation_indent_width = 20 167 ''') 168 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 169 cfg = style.CreateStyleFromConfig(filepath) 170 self.assertTrue(_LooksLikeFacebookStyle(cfg)) 171 self.assertEqual(cfg['CONTINUATION_INDENT_WIDTH'], 20) 172 173 def testBoolOptionValue(self): 174 cfg = textwrap.dedent(u'''\ 175 [style] 176 based_on_style = chromium 177 SPLIT_BEFORE_NAMED_ASSIGNS=False 178 split_before_logical_operator = true 179 ''') 180 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 181 cfg = style.CreateStyleFromConfig(filepath) 182 self.assertTrue(_LooksLikeChromiumStyle(cfg)) 183 self.assertEqual(cfg['SPLIT_BEFORE_NAMED_ASSIGNS'], False) 184 self.assertEqual(cfg['SPLIT_BEFORE_LOGICAL_OPERATOR'], True) 185 186 def testStringListOptionValue(self): 187 cfg = textwrap.dedent(u'''\ 188 [style] 189 based_on_style = chromium 190 I18N_FUNCTION_CALL = N_, V_, T_ 191 ''') 192 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 193 cfg = style.CreateStyleFromConfig(filepath) 194 self.assertTrue(_LooksLikeChromiumStyle(cfg)) 195 self.assertEqual(cfg['I18N_FUNCTION_CALL'], ['N_', 'V_', 'T_']) 196 197 def testErrorNoStyleFile(self): 198 with self.assertRaisesRegexp(style.StyleConfigError, 199 'is not a valid style or file path'): 200 style.CreateStyleFromConfig('/8822/xyznosuchfile') 201 202 def testErrorNoStyleSection(self): 203 cfg = textwrap.dedent(u'''\ 204 [s] 205 indent_width=2 206 ''') 207 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 208 with self.assertRaisesRegexp(style.StyleConfigError, 209 'Unable to find section'): 210 style.CreateStyleFromConfig(filepath) 211 212 def testErrorUnknownStyleOption(self): 213 cfg = textwrap.dedent(u'''\ 214 [style] 215 indent_width=2 216 hummus=2 217 ''') 218 with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: 219 with self.assertRaisesRegexp(style.StyleConfigError, 220 'Unknown style option'): 221 style.CreateStyleFromConfig(filepath) 222 223 224class StyleFromDict(unittest.TestCase): 225 226 @classmethod 227 def setUpClass(cls): 228 style.SetGlobalStyle(style.CreatePEP8Style()) 229 230 def testDefaultBasedOnStyle(self): 231 config_dict = { 232 'based_on_style': 'pep8', 233 'indent_width': 2, 234 'blank_line_before_nested_class_or_def': True 235 } 236 cfg = style.CreateStyleFromConfig(config_dict) 237 self.assertTrue(_LooksLikeChromiumStyle(cfg)) 238 self.assertEqual(cfg['INDENT_WIDTH'], 2) 239 240 def testDefaultBasedOnStyleBadDict(self): 241 self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', 242 style.CreateStyleFromConfig, 243 {'based_on_styl': 'pep8'}) 244 self.assertRaisesRegexp(style.StyleConfigError, 'not a valid', 245 style.CreateStyleFromConfig, 246 {'INDENT_WIDTH': 'FOUR'}) 247 248 249class StyleFromCommandLine(unittest.TestCase): 250 251 @classmethod 252 def setUpClass(cls): 253 style.SetGlobalStyle(style.CreatePEP8Style()) 254 255 def testDefaultBasedOnStyle(self): 256 cfg = style.CreateStyleFromConfig( 257 '{based_on_style: pep8,' 258 ' indent_width: 2,' 259 ' blank_line_before_nested_class_or_def: True}') 260 self.assertTrue(_LooksLikeChromiumStyle(cfg)) 261 self.assertEqual(cfg['INDENT_WIDTH'], 2) 262 263 def testDefaultBasedOnStyleNotStrict(self): 264 cfg = style.CreateStyleFromConfig( 265 '{based_on_style : pep8' 266 ' ,indent_width=2' 267 ' blank_line_before_nested_class_or_def:True}') 268 self.assertTrue(_LooksLikeChromiumStyle(cfg)) 269 self.assertEqual(cfg['INDENT_WIDTH'], 2) 270 271 def testDefaultBasedOnExplicitlyUnicodeTypeString(self): 272 cfg = style.CreateStyleFromConfig(u'{}') 273 self.assertIsInstance(cfg, dict) 274 275 def testDefaultBasedOnDetaultTypeString(self): 276 cfg = style.CreateStyleFromConfig('{}') 277 self.assertIsInstance(cfg, dict) 278 279 def testDefaultBasedOnStyleBadString(self): 280 self.assertRaisesRegexp(style.StyleConfigError, 'Unknown style option', 281 style.CreateStyleFromConfig, 282 '{based_on_styl: pep8}') 283 self.assertRaisesRegexp(style.StyleConfigError, 'not a valid', 284 style.CreateStyleFromConfig, '{INDENT_WIDTH: FOUR}') 285 self.assertRaisesRegexp(style.StyleConfigError, 'Invalid style dict', 286 style.CreateStyleFromConfig, 287 '{based_on_style: pep8') 288 289 290class StyleHelp(unittest.TestCase): 291 292 def testHelpKeys(self): 293 settings = sorted(style.Help()) 294 expected = sorted(style._style) 295 self.assertListEqual(settings, expected) 296 297 298if __name__ == '__main__': 299 unittest.main() 300