xref: /aosp_15_r20/external/yapf/yapftests/split_penalty_test.py (revision 7249d1a64f4850ccf838e62a46276f891f72998e)
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