1*7249d1a6SKrzysztof Kosiński# Copyright 2015 Google Inc. All Rights Reserved. 2*7249d1a6SKrzysztof Kosiński# 3*7249d1a6SKrzysztof Kosiński# Licensed under the Apache License, Version 2.0 (the "License"); 4*7249d1a6SKrzysztof Kosiński# you may not use this file except in compliance with the License. 5*7249d1a6SKrzysztof Kosiński# You may obtain a copy of the License at 6*7249d1a6SKrzysztof Kosiński# 7*7249d1a6SKrzysztof Kosiński# http://www.apache.org/licenses/LICENSE-2.0 8*7249d1a6SKrzysztof Kosiński# 9*7249d1a6SKrzysztof Kosiński# Unless required by applicable law or agreed to in writing, software 10*7249d1a6SKrzysztof Kosiński# distributed under the License is distributed on an "AS IS" BASIS, 11*7249d1a6SKrzysztof Kosiński# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*7249d1a6SKrzysztof Kosiński# See the License for the specific language governing permissions and 13*7249d1a6SKrzysztof Kosiński# limitations under the License. 14*7249d1a6SKrzysztof Kosiński"""Tests for yapf.split_penalty.""" 15*7249d1a6SKrzysztof Kosiński 16*7249d1a6SKrzysztof Kosińskiimport sys 17*7249d1a6SKrzysztof Kosińskiimport textwrap 18*7249d1a6SKrzysztof Kosińskiimport unittest 19*7249d1a6SKrzysztof Kosiński 20*7249d1a6SKrzysztof Kosińskifrom lib2to3 import pytree 21*7249d1a6SKrzysztof Kosiński 22*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import pytree_utils 23*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import pytree_visitor 24*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import split_penalty 25*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import style 26*7249d1a6SKrzysztof Kosiński 27*7249d1a6SKrzysztof Kosińskifrom yapftests import yapf_test_helper 28*7249d1a6SKrzysztof Kosiński 29*7249d1a6SKrzysztof KosińskiUNBREAKABLE = split_penalty.UNBREAKABLE 30*7249d1a6SKrzysztof KosińskiVERY_STRONGLY_CONNECTED = split_penalty.VERY_STRONGLY_CONNECTED 31*7249d1a6SKrzysztof KosińskiDOTTED_NAME = split_penalty.DOTTED_NAME 32*7249d1a6SKrzysztof KosińskiSTRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED 33*7249d1a6SKrzysztof Kosiński 34*7249d1a6SKrzysztof Kosiński 35*7249d1a6SKrzysztof Kosińskiclass SplitPenaltyTest(yapf_test_helper.YAPFTest): 36*7249d1a6SKrzysztof Kosiński 37*7249d1a6SKrzysztof Kosiński @classmethod 38*7249d1a6SKrzysztof Kosiński def setUpClass(cls): 39*7249d1a6SKrzysztof Kosiński style.SetGlobalStyle(style.CreateYapfStyle()) 40*7249d1a6SKrzysztof Kosiński 41*7249d1a6SKrzysztof Kosiński def _ParseAndComputePenalties(self, code, dumptree=False): 42*7249d1a6SKrzysztof Kosiński """Parses the code and computes split penalties. 43*7249d1a6SKrzysztof Kosiński 44*7249d1a6SKrzysztof Kosiński Arguments: 45*7249d1a6SKrzysztof Kosiński code: code to parse as a string 46*7249d1a6SKrzysztof Kosiński dumptree: if True, the parsed pytree (after penalty assignment) is dumped 47*7249d1a6SKrzysztof Kosiński to stderr. Useful for debugging. 48*7249d1a6SKrzysztof Kosiński 49*7249d1a6SKrzysztof Kosiński Returns: 50*7249d1a6SKrzysztof Kosiński Parse tree. 51*7249d1a6SKrzysztof Kosiński """ 52*7249d1a6SKrzysztof Kosiński tree = pytree_utils.ParseCodeToTree(code) 53*7249d1a6SKrzysztof Kosiński split_penalty.ComputeSplitPenalties(tree) 54*7249d1a6SKrzysztof Kosiński if dumptree: 55*7249d1a6SKrzysztof Kosiński pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) 56*7249d1a6SKrzysztof Kosiński return tree 57*7249d1a6SKrzysztof Kosiński 58*7249d1a6SKrzysztof Kosiński def _CheckPenalties(self, tree, list_of_expected): 59*7249d1a6SKrzysztof Kosiński """Check that the tokens in the tree have the correct penalties. 60*7249d1a6SKrzysztof Kosiński 61*7249d1a6SKrzysztof Kosiński Args: 62*7249d1a6SKrzysztof Kosiński tree: the pytree. 63*7249d1a6SKrzysztof Kosiński list_of_expected: list of (name, penalty) pairs. Non-semantic tokens are 64*7249d1a6SKrzysztof Kosiński filtered out from the expected values. 65*7249d1a6SKrzysztof Kosiński """ 66*7249d1a6SKrzysztof Kosiński 67*7249d1a6SKrzysztof Kosiński def FlattenRec(tree): 68*7249d1a6SKrzysztof Kosiński if pytree_utils.NodeName(tree) in pytree_utils.NONSEMANTIC_TOKENS: 69*7249d1a6SKrzysztof Kosiński return [] 70*7249d1a6SKrzysztof Kosiński if isinstance(tree, pytree.Leaf): 71*7249d1a6SKrzysztof Kosiński return [(tree.value, 72*7249d1a6SKrzysztof Kosiński pytree_utils.GetNodeAnnotation( 73*7249d1a6SKrzysztof Kosiński tree, pytree_utils.Annotation.SPLIT_PENALTY))] 74*7249d1a6SKrzysztof Kosiński nodes = [] 75*7249d1a6SKrzysztof Kosiński for node in tree.children: 76*7249d1a6SKrzysztof Kosiński nodes += FlattenRec(node) 77*7249d1a6SKrzysztof Kosiński return nodes 78*7249d1a6SKrzysztof Kosiński 79*7249d1a6SKrzysztof Kosiński self.assertEqual(list_of_expected, FlattenRec(tree)) 80*7249d1a6SKrzysztof Kosiński 81*7249d1a6SKrzysztof Kosiński def testUnbreakable(self): 82*7249d1a6SKrzysztof Kosiński # Test function definitions. 83*7249d1a6SKrzysztof Kosiński code = textwrap.dedent(r""" 84*7249d1a6SKrzysztof Kosiński def foo(x): 85*7249d1a6SKrzysztof Kosiński pass 86*7249d1a6SKrzysztof Kosiński """) 87*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 88*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 89*7249d1a6SKrzysztof Kosiński ('def', None), 90*7249d1a6SKrzysztof Kosiński ('foo', UNBREAKABLE), 91*7249d1a6SKrzysztof Kosiński ('(', UNBREAKABLE), 92*7249d1a6SKrzysztof Kosiński ('x', None), 93*7249d1a6SKrzysztof Kosiński (')', STRONGLY_CONNECTED), 94*7249d1a6SKrzysztof Kosiński (':', UNBREAKABLE), 95*7249d1a6SKrzysztof Kosiński ('pass', None), 96*7249d1a6SKrzysztof Kosiński ]) 97*7249d1a6SKrzysztof Kosiński 98*7249d1a6SKrzysztof Kosiński # Test function definition with trailing comment. 99*7249d1a6SKrzysztof Kosiński code = textwrap.dedent(r""" 100*7249d1a6SKrzysztof Kosiński def foo(x): # trailing comment 101*7249d1a6SKrzysztof Kosiński pass 102*7249d1a6SKrzysztof Kosiński """) 103*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 104*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 105*7249d1a6SKrzysztof Kosiński ('def', None), 106*7249d1a6SKrzysztof Kosiński ('foo', UNBREAKABLE), 107*7249d1a6SKrzysztof Kosiński ('(', UNBREAKABLE), 108*7249d1a6SKrzysztof Kosiński ('x', None), 109*7249d1a6SKrzysztof Kosiński (')', STRONGLY_CONNECTED), 110*7249d1a6SKrzysztof Kosiński (':', UNBREAKABLE), 111*7249d1a6SKrzysztof Kosiński ('pass', None), 112*7249d1a6SKrzysztof Kosiński ]) 113*7249d1a6SKrzysztof Kosiński 114*7249d1a6SKrzysztof Kosiński # Test class definitions. 115*7249d1a6SKrzysztof Kosiński code = textwrap.dedent(r""" 116*7249d1a6SKrzysztof Kosiński class A: 117*7249d1a6SKrzysztof Kosiński pass 118*7249d1a6SKrzysztof Kosiński class B(A): 119*7249d1a6SKrzysztof Kosiński pass 120*7249d1a6SKrzysztof Kosiński """) 121*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 122*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 123*7249d1a6SKrzysztof Kosiński ('class', None), 124*7249d1a6SKrzysztof Kosiński ('A', UNBREAKABLE), 125*7249d1a6SKrzysztof Kosiński (':', UNBREAKABLE), 126*7249d1a6SKrzysztof Kosiński ('pass', None), 127*7249d1a6SKrzysztof Kosiński ('class', None), 128*7249d1a6SKrzysztof Kosiński ('B', UNBREAKABLE), 129*7249d1a6SKrzysztof Kosiński ('(', UNBREAKABLE), 130*7249d1a6SKrzysztof Kosiński ('A', None), 131*7249d1a6SKrzysztof Kosiński (')', None), 132*7249d1a6SKrzysztof Kosiński (':', UNBREAKABLE), 133*7249d1a6SKrzysztof Kosiński ('pass', None), 134*7249d1a6SKrzysztof Kosiński ]) 135*7249d1a6SKrzysztof Kosiński 136*7249d1a6SKrzysztof Kosiński # Test lambda definitions. 137*7249d1a6SKrzysztof Kosiński code = textwrap.dedent(r""" 138*7249d1a6SKrzysztof Kosiński lambda a, b: None 139*7249d1a6SKrzysztof Kosiński """) 140*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 141*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 142*7249d1a6SKrzysztof Kosiński ('lambda', None), 143*7249d1a6SKrzysztof Kosiński ('a', VERY_STRONGLY_CONNECTED), 144*7249d1a6SKrzysztof Kosiński (',', VERY_STRONGLY_CONNECTED), 145*7249d1a6SKrzysztof Kosiński ('b', VERY_STRONGLY_CONNECTED), 146*7249d1a6SKrzysztof Kosiński (':', VERY_STRONGLY_CONNECTED), 147*7249d1a6SKrzysztof Kosiński ('None', VERY_STRONGLY_CONNECTED), 148*7249d1a6SKrzysztof Kosiński ]) 149*7249d1a6SKrzysztof Kosiński 150*7249d1a6SKrzysztof Kosiński # Test dotted names. 151*7249d1a6SKrzysztof Kosiński code = textwrap.dedent(r""" 152*7249d1a6SKrzysztof Kosiński import a.b.c 153*7249d1a6SKrzysztof Kosiński """) 154*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 155*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 156*7249d1a6SKrzysztof Kosiński ('import', None), 157*7249d1a6SKrzysztof Kosiński ('a', None), 158*7249d1a6SKrzysztof Kosiński ('.', UNBREAKABLE), 159*7249d1a6SKrzysztof Kosiński ('b', UNBREAKABLE), 160*7249d1a6SKrzysztof Kosiński ('.', UNBREAKABLE), 161*7249d1a6SKrzysztof Kosiński ('c', UNBREAKABLE), 162*7249d1a6SKrzysztof Kosiński ]) 163*7249d1a6SKrzysztof Kosiński 164*7249d1a6SKrzysztof Kosiński def testStronglyConnected(self): 165*7249d1a6SKrzysztof Kosiński # Test dictionary keys. 166*7249d1a6SKrzysztof Kosiński code = textwrap.dedent(r""" 167*7249d1a6SKrzysztof Kosiński a = { 168*7249d1a6SKrzysztof Kosiński 'x': 42, 169*7249d1a6SKrzysztof Kosiński y(lambda a: 23): 37, 170*7249d1a6SKrzysztof Kosiński } 171*7249d1a6SKrzysztof Kosiński """) 172*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 173*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 174*7249d1a6SKrzysztof Kosiński ('a', None), 175*7249d1a6SKrzysztof Kosiński ('=', None), 176*7249d1a6SKrzysztof Kosiński ('{', None), 177*7249d1a6SKrzysztof Kosiński ("'x'", None), 178*7249d1a6SKrzysztof Kosiński (':', STRONGLY_CONNECTED), 179*7249d1a6SKrzysztof Kosiński ('42', None), 180*7249d1a6SKrzysztof Kosiński (',', None), 181*7249d1a6SKrzysztof Kosiński ('y', None), 182*7249d1a6SKrzysztof Kosiński ('(', UNBREAKABLE), 183*7249d1a6SKrzysztof Kosiński ('lambda', STRONGLY_CONNECTED), 184*7249d1a6SKrzysztof Kosiński ('a', VERY_STRONGLY_CONNECTED), 185*7249d1a6SKrzysztof Kosiński (':', VERY_STRONGLY_CONNECTED), 186*7249d1a6SKrzysztof Kosiński ('23', VERY_STRONGLY_CONNECTED), 187*7249d1a6SKrzysztof Kosiński (')', VERY_STRONGLY_CONNECTED), 188*7249d1a6SKrzysztof Kosiński (':', STRONGLY_CONNECTED), 189*7249d1a6SKrzysztof Kosiński ('37', None), 190*7249d1a6SKrzysztof Kosiński (',', None), 191*7249d1a6SKrzysztof Kosiński ('}', None), 192*7249d1a6SKrzysztof Kosiński ]) 193*7249d1a6SKrzysztof Kosiński 194*7249d1a6SKrzysztof Kosiński # Test list comprehension. 195*7249d1a6SKrzysztof Kosiński code = textwrap.dedent(r""" 196*7249d1a6SKrzysztof Kosiński [a for a in foo if a.x == 37] 197*7249d1a6SKrzysztof Kosiński """) 198*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 199*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 200*7249d1a6SKrzysztof Kosiński ('[', None), 201*7249d1a6SKrzysztof Kosiński ('a', None), 202*7249d1a6SKrzysztof Kosiński ('for', 0), 203*7249d1a6SKrzysztof Kosiński ('a', STRONGLY_CONNECTED), 204*7249d1a6SKrzysztof Kosiński ('in', STRONGLY_CONNECTED), 205*7249d1a6SKrzysztof Kosiński ('foo', STRONGLY_CONNECTED), 206*7249d1a6SKrzysztof Kosiński ('if', 0), 207*7249d1a6SKrzysztof Kosiński ('a', STRONGLY_CONNECTED), 208*7249d1a6SKrzysztof Kosiński ('.', VERY_STRONGLY_CONNECTED), 209*7249d1a6SKrzysztof Kosiński ('x', DOTTED_NAME), 210*7249d1a6SKrzysztof Kosiński ('==', STRONGLY_CONNECTED), 211*7249d1a6SKrzysztof Kosiński ('37', STRONGLY_CONNECTED), 212*7249d1a6SKrzysztof Kosiński (']', None), 213*7249d1a6SKrzysztof Kosiński ]) 214*7249d1a6SKrzysztof Kosiński 215*7249d1a6SKrzysztof Kosiński def testFuncCalls(self): 216*7249d1a6SKrzysztof Kosiński code = 'foo(1, 2, 3)\n' 217*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 218*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 219*7249d1a6SKrzysztof Kosiński ('foo', None), 220*7249d1a6SKrzysztof Kosiński ('(', UNBREAKABLE), 221*7249d1a6SKrzysztof Kosiński ('1', None), 222*7249d1a6SKrzysztof Kosiński (',', UNBREAKABLE), 223*7249d1a6SKrzysztof Kosiński ('2', None), 224*7249d1a6SKrzysztof Kosiński (',', UNBREAKABLE), 225*7249d1a6SKrzysztof Kosiński ('3', None), 226*7249d1a6SKrzysztof Kosiński (')', VERY_STRONGLY_CONNECTED), 227*7249d1a6SKrzysztof Kosiński ]) 228*7249d1a6SKrzysztof Kosiński 229*7249d1a6SKrzysztof Kosiński # Now a method call, which has more than one trailer 230*7249d1a6SKrzysztof Kosiński code = 'foo.bar.baz(1, 2, 3)\n' 231*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 232*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 233*7249d1a6SKrzysztof Kosiński ('foo', None), 234*7249d1a6SKrzysztof Kosiński ('.', VERY_STRONGLY_CONNECTED), 235*7249d1a6SKrzysztof Kosiński ('bar', DOTTED_NAME), 236*7249d1a6SKrzysztof Kosiński ('.', VERY_STRONGLY_CONNECTED), 237*7249d1a6SKrzysztof Kosiński ('baz', DOTTED_NAME), 238*7249d1a6SKrzysztof Kosiński ('(', STRONGLY_CONNECTED), 239*7249d1a6SKrzysztof Kosiński ('1', None), 240*7249d1a6SKrzysztof Kosiński (',', UNBREAKABLE), 241*7249d1a6SKrzysztof Kosiński ('2', None), 242*7249d1a6SKrzysztof Kosiński (',', UNBREAKABLE), 243*7249d1a6SKrzysztof Kosiński ('3', None), 244*7249d1a6SKrzysztof Kosiński (')', VERY_STRONGLY_CONNECTED), 245*7249d1a6SKrzysztof Kosiński ]) 246*7249d1a6SKrzysztof Kosiński 247*7249d1a6SKrzysztof Kosiński # Test single generator argument. 248*7249d1a6SKrzysztof Kosiński code = 'max(i for i in xrange(10))\n' 249*7249d1a6SKrzysztof Kosiński tree = self._ParseAndComputePenalties(code) 250*7249d1a6SKrzysztof Kosiński self._CheckPenalties(tree, [ 251*7249d1a6SKrzysztof Kosiński ('max', None), 252*7249d1a6SKrzysztof Kosiński ('(', UNBREAKABLE), 253*7249d1a6SKrzysztof Kosiński ('i', 0), 254*7249d1a6SKrzysztof Kosiński ('for', 0), 255*7249d1a6SKrzysztof Kosiński ('i', STRONGLY_CONNECTED), 256*7249d1a6SKrzysztof Kosiński ('in', STRONGLY_CONNECTED), 257*7249d1a6SKrzysztof Kosiński ('xrange', STRONGLY_CONNECTED), 258*7249d1a6SKrzysztof Kosiński ('(', UNBREAKABLE), 259*7249d1a6SKrzysztof Kosiński ('10', STRONGLY_CONNECTED), 260*7249d1a6SKrzysztof Kosiński (')', VERY_STRONGLY_CONNECTED), 261*7249d1a6SKrzysztof Kosiński (')', VERY_STRONGLY_CONNECTED), 262*7249d1a6SKrzysztof Kosiński ]) 263*7249d1a6SKrzysztof Kosiński 264*7249d1a6SKrzysztof Kosiński 265*7249d1a6SKrzysztof Kosińskiif __name__ == '__main__': 266*7249d1a6SKrzysztof Kosiński unittest.main() 267