1*7249d1a6SKrzysztof Kosiński# -*- coding: utf-8 -*- 2*7249d1a6SKrzysztof Kosiński# Copyright 2015 Google Inc. All Rights Reserved. 3*7249d1a6SKrzysztof Kosiński# 4*7249d1a6SKrzysztof Kosiński# Licensed under the Apache License, Version 2.0 (the "License"); 5*7249d1a6SKrzysztof Kosiński# you may not use this file except in compliance with the License. 6*7249d1a6SKrzysztof Kosiński# You may obtain a copy of the License at 7*7249d1a6SKrzysztof Kosiński# 8*7249d1a6SKrzysztof Kosiński# http://www.apache.org/licenses/LICENSE-2.0 9*7249d1a6SKrzysztof Kosiński# 10*7249d1a6SKrzysztof Kosiński# Unless required by applicable law or agreed to in writing, software 11*7249d1a6SKrzysztof Kosiński# distributed under the License is distributed on an "AS IS" BASIS, 12*7249d1a6SKrzysztof Kosiński# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*7249d1a6SKrzysztof Kosiński# See the License for the specific language governing permissions and 14*7249d1a6SKrzysztof Kosiński# limitations under the License. 15*7249d1a6SKrzysztof Kosiński"""Tests for yapf.__init__.main.""" 16*7249d1a6SKrzysztof Kosiński 17*7249d1a6SKrzysztof Kosińskifrom contextlib import contextmanager 18*7249d1a6SKrzysztof Kosińskiimport sys 19*7249d1a6SKrzysztof Kosińskiimport unittest 20*7249d1a6SKrzysztof Kosińskiimport yapf 21*7249d1a6SKrzysztof Kosiński 22*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import py3compat 23*7249d1a6SKrzysztof Kosiński 24*7249d1a6SKrzysztof Kosińskifrom yapftests import yapf_test_helper 25*7249d1a6SKrzysztof Kosiński 26*7249d1a6SKrzysztof Kosiński 27*7249d1a6SKrzysztof Kosińskiclass IO(object): 28*7249d1a6SKrzysztof Kosiński """IO is a thin wrapper around StringIO. 29*7249d1a6SKrzysztof Kosiński 30*7249d1a6SKrzysztof Kosiński This is strictly to wrap the Python 3 StringIO object so that it can supply a 31*7249d1a6SKrzysztof Kosiński "buffer" attribute. 32*7249d1a6SKrzysztof Kosiński """ 33*7249d1a6SKrzysztof Kosiński 34*7249d1a6SKrzysztof Kosiński class Buffer(object): 35*7249d1a6SKrzysztof Kosiński 36*7249d1a6SKrzysztof Kosiński def __init__(self): 37*7249d1a6SKrzysztof Kosiński self.string_io = py3compat.StringIO() 38*7249d1a6SKrzysztof Kosiński 39*7249d1a6SKrzysztof Kosiński def write(self, s): 40*7249d1a6SKrzysztof Kosiński if py3compat.PY3 and isinstance(s, bytes): 41*7249d1a6SKrzysztof Kosiński s = str(s, 'utf-8') 42*7249d1a6SKrzysztof Kosiński self.string_io.write(s) 43*7249d1a6SKrzysztof Kosiński 44*7249d1a6SKrzysztof Kosiński def getvalue(self): 45*7249d1a6SKrzysztof Kosiński return self.string_io.getvalue() 46*7249d1a6SKrzysztof Kosiński 47*7249d1a6SKrzysztof Kosiński def __init__(self): 48*7249d1a6SKrzysztof Kosiński self.buffer = self.Buffer() 49*7249d1a6SKrzysztof Kosiński 50*7249d1a6SKrzysztof Kosiński def write(self, s): 51*7249d1a6SKrzysztof Kosiński self.buffer.write(s) 52*7249d1a6SKrzysztof Kosiński 53*7249d1a6SKrzysztof Kosiński def getvalue(self): 54*7249d1a6SKrzysztof Kosiński return self.buffer.getvalue() 55*7249d1a6SKrzysztof Kosiński 56*7249d1a6SKrzysztof Kosiński 57*7249d1a6SKrzysztof Kosiński@contextmanager 58*7249d1a6SKrzysztof Kosińskidef captured_output(): 59*7249d1a6SKrzysztof Kosiński new_out, new_err = IO(), IO() 60*7249d1a6SKrzysztof Kosiński old_out, old_err = sys.stdout, sys.stderr 61*7249d1a6SKrzysztof Kosiński try: 62*7249d1a6SKrzysztof Kosiński sys.stdout, sys.stderr = new_out, new_err 63*7249d1a6SKrzysztof Kosiński yield sys.stdout, sys.stderr 64*7249d1a6SKrzysztof Kosiński finally: 65*7249d1a6SKrzysztof Kosiński sys.stdout, sys.stderr = old_out, old_err 66*7249d1a6SKrzysztof Kosiński 67*7249d1a6SKrzysztof Kosiński 68*7249d1a6SKrzysztof Kosiński@contextmanager 69*7249d1a6SKrzysztof Kosińskidef patched_input(code): 70*7249d1a6SKrzysztof Kosiński """Monkey patch code as though it were coming from stdin.""" 71*7249d1a6SKrzysztof Kosiński 72*7249d1a6SKrzysztof Kosiński def lines(): 73*7249d1a6SKrzysztof Kosiński for line in code.splitlines(): 74*7249d1a6SKrzysztof Kosiński yield line 75*7249d1a6SKrzysztof Kosiński raise EOFError() 76*7249d1a6SKrzysztof Kosiński 77*7249d1a6SKrzysztof Kosiński def patch_raw_input(lines=lines()): 78*7249d1a6SKrzysztof Kosiński return next(lines) 79*7249d1a6SKrzysztof Kosiński 80*7249d1a6SKrzysztof Kosiński try: 81*7249d1a6SKrzysztof Kosiński orig_raw_import = yapf.py3compat.raw_input 82*7249d1a6SKrzysztof Kosiński yapf.py3compat.raw_input = patch_raw_input 83*7249d1a6SKrzysztof Kosiński yield 84*7249d1a6SKrzysztof Kosiński finally: 85*7249d1a6SKrzysztof Kosiński yapf.py3compat.raw_input = orig_raw_import 86*7249d1a6SKrzysztof Kosiński 87*7249d1a6SKrzysztof Kosiński 88*7249d1a6SKrzysztof Kosińskiclass RunMainTest(yapf_test_helper.YAPFTest): 89*7249d1a6SKrzysztof Kosiński 90*7249d1a6SKrzysztof Kosiński def testShouldHandleYapfError(self): 91*7249d1a6SKrzysztof Kosiński """run_main should handle YapfError and sys.exit(1).""" 92*7249d1a6SKrzysztof Kosiński expected_message = 'yapf: input filenames did not match any python files\n' 93*7249d1a6SKrzysztof Kosiński sys.argv = ['yapf', 'foo.c'] 94*7249d1a6SKrzysztof Kosiński with captured_output() as (out, err): 95*7249d1a6SKrzysztof Kosiński with self.assertRaises(SystemExit): 96*7249d1a6SKrzysztof Kosiński yapf.run_main() 97*7249d1a6SKrzysztof Kosiński self.assertEqual(out.getvalue(), '') 98*7249d1a6SKrzysztof Kosiński self.assertEqual(err.getvalue(), expected_message) 99*7249d1a6SKrzysztof Kosiński 100*7249d1a6SKrzysztof Kosiński 101*7249d1a6SKrzysztof Kosińskiclass MainTest(yapf_test_helper.YAPFTest): 102*7249d1a6SKrzysztof Kosiński 103*7249d1a6SKrzysztof Kosiński def testNoPythonFilesMatched(self): 104*7249d1a6SKrzysztof Kosiński with self.assertRaisesRegex(yapf.errors.YapfError, 105*7249d1a6SKrzysztof Kosiński 'did not match any python files'): 106*7249d1a6SKrzysztof Kosiński yapf.main(['yapf', 'foo.c']) 107*7249d1a6SKrzysztof Kosiński 108*7249d1a6SKrzysztof Kosiński def testEchoInput(self): 109*7249d1a6SKrzysztof Kosiński code = 'a = 1\nb = 2\n' 110*7249d1a6SKrzysztof Kosiński with patched_input(code): 111*7249d1a6SKrzysztof Kosiński with captured_output() as (out, _): 112*7249d1a6SKrzysztof Kosiński ret = yapf.main([]) 113*7249d1a6SKrzysztof Kosiński self.assertEqual(ret, 0) 114*7249d1a6SKrzysztof Kosiński self.assertEqual(out.getvalue(), code) 115*7249d1a6SKrzysztof Kosiński 116*7249d1a6SKrzysztof Kosiński def testEchoInputWithStyle(self): 117*7249d1a6SKrzysztof Kosiński code = 'def f(a = 1\n\n):\n return 2*a\n' 118*7249d1a6SKrzysztof Kosiński yapf_code = 'def f(a=1):\n return 2 * a\n' 119*7249d1a6SKrzysztof Kosiński with patched_input(code): 120*7249d1a6SKrzysztof Kosiński with captured_output() as (out, _): 121*7249d1a6SKrzysztof Kosiński ret = yapf.main(['-', '--style=yapf']) 122*7249d1a6SKrzysztof Kosiński self.assertEqual(ret, 0) 123*7249d1a6SKrzysztof Kosiński self.assertEqual(out.getvalue(), yapf_code) 124*7249d1a6SKrzysztof Kosiński 125*7249d1a6SKrzysztof Kosiński def testEchoBadInput(self): 126*7249d1a6SKrzysztof Kosiński bad_syntax = ' a = 1\n' 127*7249d1a6SKrzysztof Kosiński with patched_input(bad_syntax): 128*7249d1a6SKrzysztof Kosiński with captured_output() as (_, _): 129*7249d1a6SKrzysztof Kosiński with self.assertRaisesRegex(yapf.errors.YapfError, 'unexpected indent'): 130*7249d1a6SKrzysztof Kosiński yapf.main([]) 131*7249d1a6SKrzysztof Kosiński 132*7249d1a6SKrzysztof Kosiński def testHelp(self): 133*7249d1a6SKrzysztof Kosiński with captured_output() as (out, _): 134*7249d1a6SKrzysztof Kosiński ret = yapf.main(['-', '--style-help', '--style=pep8']) 135*7249d1a6SKrzysztof Kosiński self.assertEqual(ret, 0) 136*7249d1a6SKrzysztof Kosiński help_message = out.getvalue() 137*7249d1a6SKrzysztof Kosiński self.assertIn('indent_width=4', help_message) 138*7249d1a6SKrzysztof Kosiński self.assertIn('The number of spaces required before a trailing comment.', 139*7249d1a6SKrzysztof Kosiński help_message) 140