xref: /aosp_15_r20/external/yapf/yapftests/pytree_visitor_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.pytree_visitor."""
15*7249d1a6SKrzysztof Kosiński
16*7249d1a6SKrzysztof Kosińskiimport unittest
17*7249d1a6SKrzysztof Kosiński
18*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import py3compat
19*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import pytree_utils
20*7249d1a6SKrzysztof Kosińskifrom yapf.yapflib import pytree_visitor
21*7249d1a6SKrzysztof Kosiński
22*7249d1a6SKrzysztof Kosiński
23*7249d1a6SKrzysztof Kosińskiclass _NodeNameCollector(pytree_visitor.PyTreeVisitor):
24*7249d1a6SKrzysztof Kosiński  """A tree visitor that collects the names of all tree nodes into a list.
25*7249d1a6SKrzysztof Kosiński
26*7249d1a6SKrzysztof Kosiński  Attributes:
27*7249d1a6SKrzysztof Kosiński    all_node_names: collected list of the names, available when the traversal
28*7249d1a6SKrzysztof Kosiński      is over.
29*7249d1a6SKrzysztof Kosiński    name_node_values: collects a list of NAME leaves (in addition to those going
30*7249d1a6SKrzysztof Kosiński      into all_node_names).
31*7249d1a6SKrzysztof Kosiński  """
32*7249d1a6SKrzysztof Kosiński
33*7249d1a6SKrzysztof Kosiński  def __init__(self):
34*7249d1a6SKrzysztof Kosiński    self.all_node_names = []
35*7249d1a6SKrzysztof Kosiński    self.name_node_values = []
36*7249d1a6SKrzysztof Kosiński
37*7249d1a6SKrzysztof Kosiński  def DefaultNodeVisit(self, node):
38*7249d1a6SKrzysztof Kosiński    self.all_node_names.append(pytree_utils.NodeName(node))
39*7249d1a6SKrzysztof Kosiński    super(_NodeNameCollector, self).DefaultNodeVisit(node)
40*7249d1a6SKrzysztof Kosiński
41*7249d1a6SKrzysztof Kosiński  def DefaultLeafVisit(self, leaf):
42*7249d1a6SKrzysztof Kosiński    self.all_node_names.append(pytree_utils.NodeName(leaf))
43*7249d1a6SKrzysztof Kosiński
44*7249d1a6SKrzysztof Kosiński  def Visit_NAME(self, leaf):
45*7249d1a6SKrzysztof Kosiński    self.name_node_values.append(leaf.value)
46*7249d1a6SKrzysztof Kosiński    self.DefaultLeafVisit(leaf)
47*7249d1a6SKrzysztof Kosiński
48*7249d1a6SKrzysztof Kosiński
49*7249d1a6SKrzysztof Kosiński_VISITOR_TEST_SIMPLE_CODE = r"""
50*7249d1a6SKrzysztof Kosińskifoo = bar
51*7249d1a6SKrzysztof Kosińskibaz = x
52*7249d1a6SKrzysztof Kosiński"""
53*7249d1a6SKrzysztof Kosiński
54*7249d1a6SKrzysztof Kosiński_VISITOR_TEST_NESTED_CODE = r"""
55*7249d1a6SKrzysztof Kosińskiif x:
56*7249d1a6SKrzysztof Kosiński  if y:
57*7249d1a6SKrzysztof Kosiński    return z
58*7249d1a6SKrzysztof Kosiński"""
59*7249d1a6SKrzysztof Kosiński
60*7249d1a6SKrzysztof Kosiński
61*7249d1a6SKrzysztof Kosińskiclass PytreeVisitorTest(unittest.TestCase):
62*7249d1a6SKrzysztof Kosiński
63*7249d1a6SKrzysztof Kosiński  def testCollectAllNodeNamesSimpleCode(self):
64*7249d1a6SKrzysztof Kosiński    tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE)
65*7249d1a6SKrzysztof Kosiński    collector = _NodeNameCollector()
66*7249d1a6SKrzysztof Kosiński    collector.Visit(tree)
67*7249d1a6SKrzysztof Kosiński    expected_names = [
68*7249d1a6SKrzysztof Kosiński        'file_input',
69*7249d1a6SKrzysztof Kosiński        'simple_stmt', 'expr_stmt', 'NAME', 'EQUAL', 'NAME', 'NEWLINE',
70*7249d1a6SKrzysztof Kosiński        'simple_stmt', 'expr_stmt', 'NAME', 'EQUAL', 'NAME', 'NEWLINE',
71*7249d1a6SKrzysztof Kosiński        'ENDMARKER',
72*7249d1a6SKrzysztof Kosiński    ]  # yapf: disable
73*7249d1a6SKrzysztof Kosiński    self.assertEqual(expected_names, collector.all_node_names)
74*7249d1a6SKrzysztof Kosiński
75*7249d1a6SKrzysztof Kosiński    expected_name_node_values = ['foo', 'bar', 'baz', 'x']
76*7249d1a6SKrzysztof Kosiński    self.assertEqual(expected_name_node_values, collector.name_node_values)
77*7249d1a6SKrzysztof Kosiński
78*7249d1a6SKrzysztof Kosiński  def testCollectAllNodeNamesNestedCode(self):
79*7249d1a6SKrzysztof Kosiński    tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_NESTED_CODE)
80*7249d1a6SKrzysztof Kosiński    collector = _NodeNameCollector()
81*7249d1a6SKrzysztof Kosiński    collector.Visit(tree)
82*7249d1a6SKrzysztof Kosiński    expected_names = [
83*7249d1a6SKrzysztof Kosiński        'file_input',
84*7249d1a6SKrzysztof Kosiński        'if_stmt', 'NAME', 'NAME', 'COLON',
85*7249d1a6SKrzysztof Kosiński        'suite', 'NEWLINE',
86*7249d1a6SKrzysztof Kosiński        'INDENT', 'if_stmt', 'NAME', 'NAME', 'COLON', 'suite', 'NEWLINE',
87*7249d1a6SKrzysztof Kosiński        'INDENT', 'simple_stmt', 'return_stmt', 'NAME', 'NAME', 'NEWLINE',
88*7249d1a6SKrzysztof Kosiński        'DEDENT', 'DEDENT', 'ENDMARKER',
89*7249d1a6SKrzysztof Kosiński    ]  # yapf: disable
90*7249d1a6SKrzysztof Kosiński    self.assertEqual(expected_names, collector.all_node_names)
91*7249d1a6SKrzysztof Kosiński
92*7249d1a6SKrzysztof Kosiński    expected_name_node_values = ['if', 'x', 'if', 'y', 'return', 'z']
93*7249d1a6SKrzysztof Kosiński    self.assertEqual(expected_name_node_values, collector.name_node_values)
94*7249d1a6SKrzysztof Kosiński
95*7249d1a6SKrzysztof Kosiński  def testDumper(self):
96*7249d1a6SKrzysztof Kosiński    # PyTreeDumper is mainly a debugging utility, so only do basic sanity
97*7249d1a6SKrzysztof Kosiński    # checking.
98*7249d1a6SKrzysztof Kosiński    tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE)
99*7249d1a6SKrzysztof Kosiński    stream = py3compat.StringIO()
100*7249d1a6SKrzysztof Kosiński    pytree_visitor.PyTreeDumper(target_stream=stream).Visit(tree)
101*7249d1a6SKrzysztof Kosiński
102*7249d1a6SKrzysztof Kosiński    dump_output = stream.getvalue()
103*7249d1a6SKrzysztof Kosiński    self.assertIn('file_input [3 children]', dump_output)
104*7249d1a6SKrzysztof Kosiński    self.assertIn("NAME(Leaf(NAME, 'foo'))", dump_output)
105*7249d1a6SKrzysztof Kosiński    self.assertIn("EQUAL(Leaf(EQUAL, '='))", dump_output)
106*7249d1a6SKrzysztof Kosiński
107*7249d1a6SKrzysztof Kosiński  def testDumpPyTree(self):
108*7249d1a6SKrzysztof Kosiński    # Similar sanity checking for the convenience wrapper DumpPyTree
109*7249d1a6SKrzysztof Kosiński    tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE)
110*7249d1a6SKrzysztof Kosiński    stream = py3compat.StringIO()
111*7249d1a6SKrzysztof Kosiński    pytree_visitor.DumpPyTree(tree, target_stream=stream)
112*7249d1a6SKrzysztof Kosiński
113*7249d1a6SKrzysztof Kosiński    dump_output = stream.getvalue()
114*7249d1a6SKrzysztof Kosiński    self.assertIn('file_input [3 children]', dump_output)
115*7249d1a6SKrzysztof Kosiński    self.assertIn("NAME(Leaf(NAME, 'foo'))", dump_output)
116*7249d1a6SKrzysztof Kosiński    self.assertIn("EQUAL(Leaf(EQUAL, '='))", dump_output)
117*7249d1a6SKrzysztof Kosiński
118*7249d1a6SKrzysztof Kosiński
119*7249d1a6SKrzysztof Kosińskiif __name__ == '__main__':
120*7249d1a6SKrzysztof Kosiński  unittest.main()
121