| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- # Copyright 2015 Google Inc. All Rights Reserved.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """Tests for yapf.split_penalty."""
- import sys
- import textwrap
- import unittest
- from yapf_third_party._ylib2to3 import pytree
- from yapf.pytree import pytree_utils
- from yapf.pytree import pytree_visitor
- from yapf.pytree import split_penalty
- from yapf.yapflib import style
- from yapftests import yapf_test_helper
- UNBREAKABLE = split_penalty.UNBREAKABLE
- VERY_STRONGLY_CONNECTED = split_penalty.VERY_STRONGLY_CONNECTED
- DOTTED_NAME = split_penalty.DOTTED_NAME
- STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED
- class SplitPenaltyTest(yapf_test_helper.YAPFTest):
- @classmethod
- def setUpClass(cls):
- style.SetGlobalStyle(style.CreateYapfStyle())
- def _ParseAndComputePenalties(self, code, dumptree=False):
- """Parses the code and computes split penalties.
- Arguments:
- code: code to parse as a string
- dumptree: if True, the parsed pytree (after penalty assignment) is dumped
- to stderr. Useful for debugging.
- Returns:
- Parse tree.
- """
- tree = pytree_utils.ParseCodeToTree(code)
- split_penalty.ComputeSplitPenalties(tree)
- if dumptree:
- pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr)
- return tree
- def _CheckPenalties(self, tree, list_of_expected):
- """Check that the tokens in the tree have the correct penalties.
- Args:
- tree: the pytree.
- list_of_expected: list of (name, penalty) pairs. Non-semantic tokens are
- filtered out from the expected values.
- """
- def FlattenRec(tree):
- if pytree_utils.NodeName(tree) in pytree_utils.NONSEMANTIC_TOKENS:
- return []
- if isinstance(tree, pytree.Leaf):
- return [(tree.value,
- pytree_utils.GetNodeAnnotation(
- tree, pytree_utils.Annotation.SPLIT_PENALTY))]
- nodes = []
- for node in tree.children:
- nodes += FlattenRec(node)
- return nodes
- self.assertEqual(list_of_expected, FlattenRec(tree))
- def testUnbreakable(self):
- # Test function definitions.
- code = textwrap.dedent(r"""
- def foo(x):
- pass
- """)
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('def', None),
- ('foo', UNBREAKABLE),
- ('(', UNBREAKABLE),
- ('x', None),
- (')', STRONGLY_CONNECTED),
- (':', UNBREAKABLE),
- ('pass', None),
- ])
- # Test function definition with trailing comment.
- code = textwrap.dedent(r"""
- def foo(x): # trailing comment
- pass
- """)
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('def', None),
- ('foo', UNBREAKABLE),
- ('(', UNBREAKABLE),
- ('x', None),
- (')', STRONGLY_CONNECTED),
- (':', UNBREAKABLE),
- ('pass', None),
- ])
- # Test class definitions.
- code = textwrap.dedent(r"""
- class A:
- pass
- class B(A):
- pass
- """)
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('class', None),
- ('A', UNBREAKABLE),
- (':', UNBREAKABLE),
- ('pass', None),
- ('class', None),
- ('B', UNBREAKABLE),
- ('(', UNBREAKABLE),
- ('A', None),
- (')', None),
- (':', UNBREAKABLE),
- ('pass', None),
- ])
- # Test lambda definitions.
- code = textwrap.dedent(r"""
- lambda a, b: None
- """)
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('lambda', None),
- ('a', VERY_STRONGLY_CONNECTED),
- (',', VERY_STRONGLY_CONNECTED),
- ('b', VERY_STRONGLY_CONNECTED),
- (':', VERY_STRONGLY_CONNECTED),
- ('None', VERY_STRONGLY_CONNECTED),
- ])
- # Test dotted names.
- code = textwrap.dedent(r"""
- import a.b.c
- """)
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('import', None),
- ('a', None),
- ('.', UNBREAKABLE),
- ('b', UNBREAKABLE),
- ('.', UNBREAKABLE),
- ('c', UNBREAKABLE),
- ])
- def testStronglyConnected(self):
- # Test dictionary keys.
- code = textwrap.dedent(r"""
- a = {
- 'x': 42,
- y(lambda a: 23): 37,
- }
- """)
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('a', None),
- ('=', None),
- ('{', None),
- ("'x'", None),
- (':', STRONGLY_CONNECTED),
- ('42', None),
- (',', None),
- ('y', None),
- ('(', UNBREAKABLE),
- ('lambda', STRONGLY_CONNECTED),
- ('a', VERY_STRONGLY_CONNECTED),
- (':', VERY_STRONGLY_CONNECTED),
- ('23', VERY_STRONGLY_CONNECTED),
- (')', VERY_STRONGLY_CONNECTED),
- (':', STRONGLY_CONNECTED),
- ('37', None),
- (',', None),
- ('}', None),
- ])
- # Test list comprehension.
- code = textwrap.dedent(r"""
- [a for a in foo if a.x == 37]
- """)
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('[', None),
- ('a', None),
- ('for', 0),
- ('a', STRONGLY_CONNECTED),
- ('in', STRONGLY_CONNECTED),
- ('foo', STRONGLY_CONNECTED),
- ('if', 0),
- ('a', STRONGLY_CONNECTED),
- ('.', VERY_STRONGLY_CONNECTED),
- ('x', DOTTED_NAME),
- ('==', STRONGLY_CONNECTED),
- ('37', STRONGLY_CONNECTED),
- (']', None),
- ])
- def testFuncCalls(self):
- code = 'foo(1, 2, 3)\n'
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('foo', None),
- ('(', UNBREAKABLE),
- ('1', None),
- (',', UNBREAKABLE),
- ('2', None),
- (',', UNBREAKABLE),
- ('3', None),
- (')', VERY_STRONGLY_CONNECTED),
- ])
- # Now a method call, which has more than one trailer
- code = 'foo.bar.baz(1, 2, 3)\n'
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('foo', None),
- ('.', VERY_STRONGLY_CONNECTED),
- ('bar', DOTTED_NAME),
- ('.', VERY_STRONGLY_CONNECTED),
- ('baz', DOTTED_NAME),
- ('(', STRONGLY_CONNECTED),
- ('1', None),
- (',', UNBREAKABLE),
- ('2', None),
- (',', UNBREAKABLE),
- ('3', None),
- (')', VERY_STRONGLY_CONNECTED),
- ])
- # Test single generator argument.
- code = 'max(i for i in xrange(10))\n'
- tree = self._ParseAndComputePenalties(code)
- self._CheckPenalties(tree, [
- ('max', None),
- ('(', UNBREAKABLE),
- ('i', 0),
- ('for', 0),
- ('i', STRONGLY_CONNECTED),
- ('in', STRONGLY_CONNECTED),
- ('xrange', STRONGLY_CONNECTED),
- ('(', UNBREAKABLE),
- ('10', STRONGLY_CONNECTED),
- (')', VERY_STRONGLY_CONNECTED),
- (')', VERY_STRONGLY_CONNECTED),
- ])
- if __name__ == '__main__':
- unittest.main()
|