xref: /aosp_15_r20/build/soong/scripts/hiddenapi/signature_trie_test.py (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker#!/usr/bin/env python
2*333d2b36SAndroid Build Coastguard Worker#
3*333d2b36SAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project
4*333d2b36SAndroid Build Coastguard Worker#
5*333d2b36SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the 'License');
6*333d2b36SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*333d2b36SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*333d2b36SAndroid Build Coastguard Worker#
9*333d2b36SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*333d2b36SAndroid Build Coastguard Worker#
11*333d2b36SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*333d2b36SAndroid Build Coastguard Worker# distributed under the License is distributed on an 'AS IS' BASIS,
13*333d2b36SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*333d2b36SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*333d2b36SAndroid Build Coastguard Worker# limitations under the License.
16*333d2b36SAndroid Build Coastguard Worker"""Unit tests for verify_overlaps_test.py."""
17*333d2b36SAndroid Build Coastguard Workerimport io
18*333d2b36SAndroid Build Coastguard Workerimport unittest
19*333d2b36SAndroid Build Coastguard Worker
20*333d2b36SAndroid Build Coastguard Workerfrom signature_trie import InteriorNode
21*333d2b36SAndroid Build Coastguard Workerfrom signature_trie import signature_trie
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker
24*333d2b36SAndroid Build Coastguard Workerclass TestSignatureToElements(unittest.TestCase):
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Worker    @staticmethod
27*333d2b36SAndroid Build Coastguard Worker    def signature_to_elements(signature):
28*333d2b36SAndroid Build Coastguard Worker        return InteriorNode.signature_to_elements(signature)
29*333d2b36SAndroid Build Coastguard Worker
30*333d2b36SAndroid Build Coastguard Worker    @staticmethod
31*333d2b36SAndroid Build Coastguard Worker    def elements_to_signature(elements):
32*333d2b36SAndroid Build Coastguard Worker        return InteriorNode.elements_to_selector(elements)
33*333d2b36SAndroid Build Coastguard Worker
34*333d2b36SAndroid Build Coastguard Worker    def test_nested_inner_classes(self):
35*333d2b36SAndroid Build Coastguard Worker        elements = [
36*333d2b36SAndroid Build Coastguard Worker            ("package", "java"),
37*333d2b36SAndroid Build Coastguard Worker            ("package", "lang"),
38*333d2b36SAndroid Build Coastguard Worker            ("class", "ProcessBuilder"),
39*333d2b36SAndroid Build Coastguard Worker            ("class", "Redirect"),
40*333d2b36SAndroid Build Coastguard Worker            ("class", "1"),
41*333d2b36SAndroid Build Coastguard Worker            ("member", "<init>()V"),
42*333d2b36SAndroid Build Coastguard Worker        ]
43*333d2b36SAndroid Build Coastguard Worker        signature = "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V"
44*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
45*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, "L" + self.elements_to_signature(elements))
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Worker    def test_basic_member(self):
48*333d2b36SAndroid Build Coastguard Worker        elements = [
49*333d2b36SAndroid Build Coastguard Worker            ("package", "java"),
50*333d2b36SAndroid Build Coastguard Worker            ("package", "lang"),
51*333d2b36SAndroid Build Coastguard Worker            ("class", "Object"),
52*333d2b36SAndroid Build Coastguard Worker            ("member", "hashCode()I"),
53*333d2b36SAndroid Build Coastguard Worker        ]
54*333d2b36SAndroid Build Coastguard Worker        signature = "Ljava/lang/Object;->hashCode()I"
55*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
56*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, "L" + self.elements_to_signature(elements))
57*333d2b36SAndroid Build Coastguard Worker
58*333d2b36SAndroid Build Coastguard Worker    def test_double_dollar_class(self):
59*333d2b36SAndroid Build Coastguard Worker        elements = [
60*333d2b36SAndroid Build Coastguard Worker            ("package", "java"),
61*333d2b36SAndroid Build Coastguard Worker            ("package", "lang"),
62*333d2b36SAndroid Build Coastguard Worker            ("class", "CharSequence"),
63*333d2b36SAndroid Build Coastguard Worker            ("class", ""),
64*333d2b36SAndroid Build Coastguard Worker            ("class", "ExternalSyntheticLambda0"),
65*333d2b36SAndroid Build Coastguard Worker            ("member", "<init>(Ljava/lang/CharSequence;)V"),
66*333d2b36SAndroid Build Coastguard Worker        ]
67*333d2b36SAndroid Build Coastguard Worker        signature = "Ljava/lang/CharSequence$$ExternalSyntheticLambda0;" \
68*333d2b36SAndroid Build Coastguard Worker                    "-><init>(Ljava/lang/CharSequence;)V"
69*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
70*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, "L" + self.elements_to_signature(elements))
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Worker    def test_no_member(self):
73*333d2b36SAndroid Build Coastguard Worker        elements = [
74*333d2b36SAndroid Build Coastguard Worker            ("package", "java"),
75*333d2b36SAndroid Build Coastguard Worker            ("package", "lang"),
76*333d2b36SAndroid Build Coastguard Worker            ("class", "CharSequence"),
77*333d2b36SAndroid Build Coastguard Worker            ("class", ""),
78*333d2b36SAndroid Build Coastguard Worker            ("class", "ExternalSyntheticLambda0"),
79*333d2b36SAndroid Build Coastguard Worker        ]
80*333d2b36SAndroid Build Coastguard Worker        signature = "Ljava/lang/CharSequence$$ExternalSyntheticLambda0"
81*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
82*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, "L" + self.elements_to_signature(elements))
83*333d2b36SAndroid Build Coastguard Worker
84*333d2b36SAndroid Build Coastguard Worker    def test_wildcard(self):
85*333d2b36SAndroid Build Coastguard Worker        elements = [
86*333d2b36SAndroid Build Coastguard Worker            ("package", "java"),
87*333d2b36SAndroid Build Coastguard Worker            ("package", "lang"),
88*333d2b36SAndroid Build Coastguard Worker            ("wildcard", "*"),
89*333d2b36SAndroid Build Coastguard Worker        ]
90*333d2b36SAndroid Build Coastguard Worker        signature = "java/lang/*"
91*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
92*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, self.elements_to_signature(elements))
93*333d2b36SAndroid Build Coastguard Worker
94*333d2b36SAndroid Build Coastguard Worker    def test_recursive_wildcard(self):
95*333d2b36SAndroid Build Coastguard Worker        elements = [
96*333d2b36SAndroid Build Coastguard Worker            ("package", "java"),
97*333d2b36SAndroid Build Coastguard Worker            ("package", "lang"),
98*333d2b36SAndroid Build Coastguard Worker            ("wildcard", "**"),
99*333d2b36SAndroid Build Coastguard Worker        ]
100*333d2b36SAndroid Build Coastguard Worker        signature = "java/lang/**"
101*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
102*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, self.elements_to_signature(elements))
103*333d2b36SAndroid Build Coastguard Worker
104*333d2b36SAndroid Build Coastguard Worker    def test_no_packages_wildcard(self):
105*333d2b36SAndroid Build Coastguard Worker        elements = [
106*333d2b36SAndroid Build Coastguard Worker            ("wildcard", "*"),
107*333d2b36SAndroid Build Coastguard Worker        ]
108*333d2b36SAndroid Build Coastguard Worker        signature = "*"
109*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
110*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, self.elements_to_signature(elements))
111*333d2b36SAndroid Build Coastguard Worker
112*333d2b36SAndroid Build Coastguard Worker    def test_no_packages_recursive_wildcard(self):
113*333d2b36SAndroid Build Coastguard Worker        elements = [
114*333d2b36SAndroid Build Coastguard Worker            ("wildcard", "**"),
115*333d2b36SAndroid Build Coastguard Worker        ]
116*333d2b36SAndroid Build Coastguard Worker        signature = "**"
117*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
118*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, self.elements_to_signature(elements))
119*333d2b36SAndroid Build Coastguard Worker
120*333d2b36SAndroid Build Coastguard Worker    def test_non_standard_class_name(self):
121*333d2b36SAndroid Build Coastguard Worker        elements = [
122*333d2b36SAndroid Build Coastguard Worker            ("package", "javax"),
123*333d2b36SAndroid Build Coastguard Worker            ("package", "crypto"),
124*333d2b36SAndroid Build Coastguard Worker            ("class", "extObjectInputStream"),
125*333d2b36SAndroid Build Coastguard Worker        ]
126*333d2b36SAndroid Build Coastguard Worker        signature = "Ljavax/crypto/extObjectInputStream"
127*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(elements, self.signature_to_elements(signature))
128*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(signature, "L" + self.elements_to_signature(elements))
129*333d2b36SAndroid Build Coastguard Worker
130*333d2b36SAndroid Build Coastguard Worker    def test_invalid_pattern_wildcard(self):
131*333d2b36SAndroid Build Coastguard Worker        pattern = "Ljava/lang/Class*"
132*333d2b36SAndroid Build Coastguard Worker        with self.assertRaises(Exception) as context:
133*333d2b36SAndroid Build Coastguard Worker            self.signature_to_elements(pattern)
134*333d2b36SAndroid Build Coastguard Worker        self.assertIn("invalid wildcard 'Class*'", str(context.exception))
135*333d2b36SAndroid Build Coastguard Worker
136*333d2b36SAndroid Build Coastguard Worker    def test_invalid_pattern_wildcard_and_member(self):
137*333d2b36SAndroid Build Coastguard Worker        pattern = "Ljava/lang/*;->hashCode()I"
138*333d2b36SAndroid Build Coastguard Worker        with self.assertRaises(Exception) as context:
139*333d2b36SAndroid Build Coastguard Worker            self.signature_to_elements(pattern)
140*333d2b36SAndroid Build Coastguard Worker        self.assertIn(
141*333d2b36SAndroid Build Coastguard Worker            "contains wildcard '*' and member signature 'hashCode()I'",
142*333d2b36SAndroid Build Coastguard Worker            str(context.exception))
143*333d2b36SAndroid Build Coastguard Worker
144*333d2b36SAndroid Build Coastguard Worker
145*333d2b36SAndroid Build Coastguard Workerclass TestValues(unittest.TestCase):
146*333d2b36SAndroid Build Coastguard Worker    def test_add_then_get(self):
147*333d2b36SAndroid Build Coastguard Worker        trie = signature_trie()
148*333d2b36SAndroid Build Coastguard Worker        trie.add("La/b/C;->l()", 1)
149*333d2b36SAndroid Build Coastguard Worker        trie.add("La/b/C$D;->m()", "A")
150*333d2b36SAndroid Build Coastguard Worker        trie.add("La/b/C$D;->n()", {})
151*333d2b36SAndroid Build Coastguard Worker
152*333d2b36SAndroid Build Coastguard Worker        package_a_node = next(iter(trie.child_nodes()))
153*333d2b36SAndroid Build Coastguard Worker        self.assertEqual("package", package_a_node.type)
154*333d2b36SAndroid Build Coastguard Worker        self.assertEqual("a", package_a_node.selector)
155*333d2b36SAndroid Build Coastguard Worker
156*333d2b36SAndroid Build Coastguard Worker        package_b_node = next(iter(package_a_node.child_nodes()))
157*333d2b36SAndroid Build Coastguard Worker        self.assertEqual("package", package_b_node.type)
158*333d2b36SAndroid Build Coastguard Worker        self.assertEqual("a/b", package_b_node.selector)
159*333d2b36SAndroid Build Coastguard Worker
160*333d2b36SAndroid Build Coastguard Worker        class_c_node = next(iter(package_b_node.child_nodes()))
161*333d2b36SAndroid Build Coastguard Worker        self.assertEqual("class", class_c_node.type)
162*333d2b36SAndroid Build Coastguard Worker        self.assertEqual("a/b/C", class_c_node.selector)
163*333d2b36SAndroid Build Coastguard Worker
164*333d2b36SAndroid Build Coastguard Worker        self.assertEqual([1, "A", {}], class_c_node.values(lambda _: True))
165*333d2b36SAndroid Build Coastguard Worker
166*333d2b36SAndroid Build Coastguard Workerclass TestGetMatchingRows(unittest.TestCase):
167*333d2b36SAndroid Build Coastguard Worker    extractInput = """
168*333d2b36SAndroid Build Coastguard WorkerLjava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
169*333d2b36SAndroid Build Coastguard WorkerLjava/lang/Character;->serialVersionUID:J
170*333d2b36SAndroid Build Coastguard WorkerLjava/lang/Object;->hashCode()I
171*333d2b36SAndroid Build Coastguard WorkerLjava/lang/Object;->toString()Ljava/lang/String;
172*333d2b36SAndroid Build Coastguard WorkerLjava/lang/ProcessBuilder$Redirect$1;-><init>()V
173*333d2b36SAndroid Build Coastguard WorkerLjava/util/zip/ZipFile;-><clinit>()V
174*333d2b36SAndroid Build Coastguard Worker"""
175*333d2b36SAndroid Build Coastguard Worker
176*333d2b36SAndroid Build Coastguard Worker    def read_trie(self):
177*333d2b36SAndroid Build Coastguard Worker        trie = signature_trie()
178*333d2b36SAndroid Build Coastguard Worker        with io.StringIO(self.extractInput.strip()) as f:
179*333d2b36SAndroid Build Coastguard Worker            for line in iter(f.readline, ""):
180*333d2b36SAndroid Build Coastguard Worker                line = line.rstrip()
181*333d2b36SAndroid Build Coastguard Worker                trie.add(line, line)
182*333d2b36SAndroid Build Coastguard Worker        return trie
183*333d2b36SAndroid Build Coastguard Worker
184*333d2b36SAndroid Build Coastguard Worker    def check_patterns(self, pattern, expected):
185*333d2b36SAndroid Build Coastguard Worker        trie = self.read_trie()
186*333d2b36SAndroid Build Coastguard Worker        self.check_node_patterns(trie, pattern, expected)
187*333d2b36SAndroid Build Coastguard Worker
188*333d2b36SAndroid Build Coastguard Worker    def check_node_patterns(self, node, pattern, expected):
189*333d2b36SAndroid Build Coastguard Worker        actual = list(node.get_matching_rows(pattern))
190*333d2b36SAndroid Build Coastguard Worker        actual.sort()
191*333d2b36SAndroid Build Coastguard Worker        self.assertEqual(expected, actual)
192*333d2b36SAndroid Build Coastguard Worker
193*333d2b36SAndroid Build Coastguard Worker    def test_member_pattern(self):
194*333d2b36SAndroid Build Coastguard Worker        self.check_patterns("java/util/zip/ZipFile;-><clinit>()V",
195*333d2b36SAndroid Build Coastguard Worker                            ["Ljava/util/zip/ZipFile;-><clinit>()V"])
196*333d2b36SAndroid Build Coastguard Worker
197*333d2b36SAndroid Build Coastguard Worker    def test_class_pattern(self):
198*333d2b36SAndroid Build Coastguard Worker        self.check_patterns("java/lang/Object", [
199*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Object;->hashCode()I",
200*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Object;->toString()Ljava/lang/String;",
201*333d2b36SAndroid Build Coastguard Worker        ])
202*333d2b36SAndroid Build Coastguard Worker
203*333d2b36SAndroid Build Coastguard Worker    # pylint: disable=line-too-long
204*333d2b36SAndroid Build Coastguard Worker    def test_nested_class_pattern(self):
205*333d2b36SAndroid Build Coastguard Worker        self.check_patterns("java/lang/Character", [
206*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
207*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Character;->serialVersionUID:J",
208*333d2b36SAndroid Build Coastguard Worker        ])
209*333d2b36SAndroid Build Coastguard Worker
210*333d2b36SAndroid Build Coastguard Worker    def test_wildcard(self):
211*333d2b36SAndroid Build Coastguard Worker        self.check_patterns("java/lang/*", [
212*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
213*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Character;->serialVersionUID:J",
214*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Object;->hashCode()I",
215*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Object;->toString()Ljava/lang/String;",
216*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
217*333d2b36SAndroid Build Coastguard Worker        ])
218*333d2b36SAndroid Build Coastguard Worker
219*333d2b36SAndroid Build Coastguard Worker    def test_recursive_wildcard(self):
220*333d2b36SAndroid Build Coastguard Worker        self.check_patterns("java/**", [
221*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
222*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Character;->serialVersionUID:J",
223*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Object;->hashCode()I",
224*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Object;->toString()Ljava/lang/String;",
225*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
226*333d2b36SAndroid Build Coastguard Worker            "Ljava/util/zip/ZipFile;-><clinit>()V",
227*333d2b36SAndroid Build Coastguard Worker        ])
228*333d2b36SAndroid Build Coastguard Worker
229*333d2b36SAndroid Build Coastguard Worker    def test_node_wildcard(self):
230*333d2b36SAndroid Build Coastguard Worker        trie = self.read_trie()
231*333d2b36SAndroid Build Coastguard Worker        node = list(trie.child_nodes())[0]
232*333d2b36SAndroid Build Coastguard Worker        self.check_node_patterns(node, "**", [
233*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
234*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Character;->serialVersionUID:J",
235*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Object;->hashCode()I",
236*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/Object;->toString()Ljava/lang/String;",
237*333d2b36SAndroid Build Coastguard Worker            "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
238*333d2b36SAndroid Build Coastguard Worker            "Ljava/util/zip/ZipFile;-><clinit>()V",
239*333d2b36SAndroid Build Coastguard Worker        ])
240*333d2b36SAndroid Build Coastguard Worker
241*333d2b36SAndroid Build Coastguard Worker    # pylint: enable=line-too-long
242*333d2b36SAndroid Build Coastguard Worker
243*333d2b36SAndroid Build Coastguard Worker
244*333d2b36SAndroid Build Coastguard Workerif __name__ == "__main__":
245*333d2b36SAndroid Build Coastguard Worker    unittest.main(verbosity=2)
246