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.__init__.main.""" 16 17from contextlib import contextmanager 18import sys 19import unittest 20import yapf 21 22from yapf.yapflib import py3compat 23 24 25class IO(object): 26 """IO is a thin wrapper around StringIO. 27 28 This is strictly to wrap the Python 3 StringIO object so that it can supply a 29 "buffer" attribute. 30 """ 31 32 class Buffer(object): 33 34 def __init__(self): 35 self.string_io = py3compat.StringIO() 36 37 def write(self, s): 38 if py3compat.PY3 and isinstance(s, bytes): 39 s = str(s, 'utf-8') 40 self.string_io.write(s) 41 42 def getvalue(self): 43 return self.string_io.getvalue() 44 45 def __init__(self): 46 self.buffer = self.Buffer() 47 48 def write(self, s): 49 self.buffer.write(s) 50 51 def getvalue(self): 52 return self.buffer.getvalue() 53 54 55@contextmanager 56def captured_output(): 57 new_out, new_err = IO(), IO() 58 old_out, old_err = sys.stdout, sys.stderr 59 try: 60 sys.stdout, sys.stderr = new_out, new_err 61 yield sys.stdout, sys.stderr 62 finally: 63 sys.stdout, sys.stderr = old_out, old_err 64 65 66@contextmanager 67def patched_input(code): 68 """Monkey patch code as though it were coming from stdin.""" 69 70 def lines(): 71 for line in code.splitlines(): 72 yield line 73 raise EOFError() 74 75 def patch_raw_input(lines=lines()): 76 return next(lines) 77 78 try: 79 orig_raw_import = yapf.py3compat.raw_input 80 yapf.py3compat.raw_input = patch_raw_input 81 yield 82 finally: 83 yapf.py3compat.raw_input = orig_raw_import 84 85 86class RunMainTest(unittest.TestCase): 87 88 def testShouldHandleYapfError(self): 89 """run_main should handle YapfError and sys.exit(1).""" 90 expected_message = 'yapf: Input filenames did not match any python files\n' 91 sys.argv = ['yapf', 'foo.c'] 92 with captured_output() as (out, err): 93 with self.assertRaises(SystemExit): 94 yapf.run_main() 95 self.assertEqual(out.getvalue(), '') 96 self.assertEqual(err.getvalue(), expected_message) 97 98 99class MainTest(unittest.TestCase): 100 101 def testNoPythonFilesMatched(self): 102 with self.assertRaisesRegexp(yapf.errors.YapfError, 103 'did not match any python files'): 104 yapf.main(['yapf', 'foo.c']) 105 106 def testEchoInput(self): 107 code = 'a = 1\nb = 2\n' 108 with patched_input(code): 109 with captured_output() as (out, _): 110 ret = yapf.main([]) 111 self.assertEqual(ret, 0) 112 self.assertEqual(out.getvalue(), code) 113 114 def testEchoInputWithStyle(self): 115 code = 'def f(a = 1):\n return 2*a\n' 116 chromium_code = 'def f(a=1):\n return 2 * a\n' 117 with patched_input(code): 118 with captured_output() as (out, _): 119 ret = yapf.main(['-', '--style=chromium']) 120 self.assertEqual(ret, 0) 121 self.assertEqual(out.getvalue(), chromium_code) 122 123 def testEchoBadInput(self): 124 bad_syntax = ' a = 1\n' 125 with patched_input(bad_syntax): 126 with captured_output() as (_, _): 127 with self.assertRaisesRegexp(SyntaxError, 'unexpected indent'): 128 yapf.main([]) 129 130 def testHelp(self): 131 with captured_output() as (out, _): 132 ret = yapf.main(['-', '--style-help', '--style=pep8']) 133 self.assertEqual(ret, 0) 134 help_message = out.getvalue() 135 self.assertIn('indent_width=4', help_message) 136 self.assertIn('The number of spaces required before a trailing comment.', 137 help_message) 138 139 def testVersion(self): 140 with captured_output() as (out, _): 141 ret = yapf.main(['-', '--version']) 142 self.assertEqual(ret, 0) 143 version = 'yapf {}\n'.format(yapf.__version__) 144 self.assertEqual(version, out.getvalue()) 145