blob: 6d4e660e3334f538ce077b767e59a144268eab66 [file] [log] [blame]
Paul Duffinb5cd5222022-02-28 19:06:49 +00001#!/usr/bin/env python
2#
3# Copyright (C) 2022 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the 'License');
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an 'AS IS' BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""Unit tests for verify_overlaps_test.py."""
17import io
18import unittest
19
20from signature_trie import InteriorNode
21from signature_trie import signature_trie
22
23
24class TestSignatureToElements(unittest.TestCase):
25
26 @staticmethod
27 def signature_to_elements(signature):
28 return InteriorNode.signature_to_elements(signature)
29
Paul Duffin92532e72022-03-09 14:28:34 +000030 @staticmethod
31 def elements_to_signature(elements):
32 return InteriorNode.elements_to_selector(elements)
33
Paul Duffinb5cd5222022-02-28 19:06:49 +000034 def test_nested_inner_classes(self):
35 elements = [
Paul Duffinea935422022-03-09 14:51:17 +000036 ("package", "java"),
37 ("package", "lang"),
38 ("class", "ProcessBuilder"),
39 ("class", "Redirect"),
40 ("class", "1"),
41 ("member", "<init>()V"),
Paul Duffinb5cd5222022-02-28 19:06:49 +000042 ]
43 signature = "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V"
44 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +000045 self.assertEqual(signature, "L" + self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +000046
47 def test_basic_member(self):
48 elements = [
Paul Duffinea935422022-03-09 14:51:17 +000049 ("package", "java"),
50 ("package", "lang"),
51 ("class", "Object"),
52 ("member", "hashCode()I"),
Paul Duffinb5cd5222022-02-28 19:06:49 +000053 ]
54 signature = "Ljava/lang/Object;->hashCode()I"
55 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +000056 self.assertEqual(signature, "L" + self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +000057
58 def test_double_dollar_class(self):
59 elements = [
Paul Duffinea935422022-03-09 14:51:17 +000060 ("package", "java"),
61 ("package", "lang"),
62 ("class", "CharSequence"),
63 ("class", ""),
64 ("class", "ExternalSyntheticLambda0"),
65 ("member", "<init>(Ljava/lang/CharSequence;)V"),
Paul Duffinb5cd5222022-02-28 19:06:49 +000066 ]
67 signature = "Ljava/lang/CharSequence$$ExternalSyntheticLambda0;" \
68 "-><init>(Ljava/lang/CharSequence;)V"
69 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +000070 self.assertEqual(signature, "L" + self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +000071
72 def test_no_member(self):
73 elements = [
Paul Duffinea935422022-03-09 14:51:17 +000074 ("package", "java"),
75 ("package", "lang"),
76 ("class", "CharSequence"),
77 ("class", ""),
78 ("class", "ExternalSyntheticLambda0"),
Paul Duffinb5cd5222022-02-28 19:06:49 +000079 ]
80 signature = "Ljava/lang/CharSequence$$ExternalSyntheticLambda0"
81 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +000082 self.assertEqual(signature, "L" + self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +000083
84 def test_wildcard(self):
85 elements = [
Paul Duffinea935422022-03-09 14:51:17 +000086 ("package", "java"),
87 ("package", "lang"),
88 ("wildcard", "*"),
Paul Duffinb5cd5222022-02-28 19:06:49 +000089 ]
90 signature = "java/lang/*"
91 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +000092 self.assertEqual(signature, self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +000093
94 def test_recursive_wildcard(self):
95 elements = [
Paul Duffinea935422022-03-09 14:51:17 +000096 ("package", "java"),
97 ("package", "lang"),
98 ("wildcard", "**"),
Paul Duffinb5cd5222022-02-28 19:06:49 +000099 ]
100 signature = "java/lang/**"
101 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +0000102 self.assertEqual(signature, self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +0000103
104 def test_no_packages_wildcard(self):
105 elements = [
Paul Duffinea935422022-03-09 14:51:17 +0000106 ("wildcard", "*"),
Paul Duffinb5cd5222022-02-28 19:06:49 +0000107 ]
108 signature = "*"
109 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +0000110 self.assertEqual(signature, self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +0000111
112 def test_no_packages_recursive_wildcard(self):
113 elements = [
Paul Duffinea935422022-03-09 14:51:17 +0000114 ("wildcard", "**"),
Paul Duffinb5cd5222022-02-28 19:06:49 +0000115 ]
116 signature = "**"
117 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +0000118 self.assertEqual(signature, self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +0000119
Paul Duffin19255f12022-03-08 16:35:52 +0000120 def test_invalid_no_class_or_wildcard(self):
121 signature = "java/lang"
122 with self.assertRaises(Exception) as context:
123 self.signature_to_elements(signature)
124 self.assertIn(
125 "last element 'lang' is lower case but should be an "
126 "upper case class name or wildcard", str(context.exception))
127
Paul Duffinb5cd5222022-02-28 19:06:49 +0000128 def test_non_standard_class_name(self):
129 elements = [
Paul Duffinea935422022-03-09 14:51:17 +0000130 ("package", "javax"),
131 ("package", "crypto"),
132 ("class", "extObjectInputStream"),
Paul Duffinb5cd5222022-02-28 19:06:49 +0000133 ]
134 signature = "Ljavax/crypto/extObjectInputStream"
135 self.assertEqual(elements, self.signature_to_elements(signature))
Paul Duffin92532e72022-03-09 14:28:34 +0000136 self.assertEqual(signature, "L" + self.elements_to_signature(elements))
Paul Duffinb5cd5222022-02-28 19:06:49 +0000137
Paul Duffin19255f12022-03-08 16:35:52 +0000138 def test_invalid_pattern_wildcard(self):
139 pattern = "Ljava/lang/Class*"
140 with self.assertRaises(Exception) as context:
141 self.signature_to_elements(pattern)
142 self.assertIn("invalid wildcard 'Class*'", str(context.exception))
143
Paul Duffinb5cd5222022-02-28 19:06:49 +0000144 def test_invalid_pattern_wildcard_and_member(self):
145 pattern = "Ljava/lang/*;->hashCode()I"
146 with self.assertRaises(Exception) as context:
147 self.signature_to_elements(pattern)
Paul Duffin19255f12022-03-08 16:35:52 +0000148 self.assertIn(
149 "contains wildcard '*' and member signature 'hashCode()I'",
150 str(context.exception))
Paul Duffinb5cd5222022-02-28 19:06:49 +0000151
152
Paul Duffindbbb8372022-04-01 15:04:23 +0100153class TestValues(unittest.TestCase):
154 def test_add_then_get(self):
155 trie = signature_trie()
156 trie.add("La/b/C;->l()", 1)
157 trie.add("La/b/C$D;->m()", "A")
158 trie.add("La/b/C$D;->n()", {})
159
160 package_a_node = next(iter(trie.child_nodes()))
161 self.assertEqual("package", package_a_node.type)
162 self.assertEqual("a", package_a_node.selector)
163
164 package_b_node = next(iter(package_a_node.child_nodes()))
165 self.assertEqual("package", package_b_node.type)
166 self.assertEqual("a/b", package_b_node.selector)
167
168 class_c_node = next(iter(package_b_node.child_nodes()))
169 self.assertEqual("class", class_c_node.type)
170 self.assertEqual("a/b/C", class_c_node.selector)
171
172 self.assertEqual([1, "A", {}], class_c_node.values(lambda _: True))
173
Paul Duffinb5cd5222022-02-28 19:06:49 +0000174class TestGetMatchingRows(unittest.TestCase):
175 extractInput = """
176Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
177Ljava/lang/Character;->serialVersionUID:J
178Ljava/lang/Object;->hashCode()I
179Ljava/lang/Object;->toString()Ljava/lang/String;
180Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V
181Ljava/util/zip/ZipFile;-><clinit>()V
182"""
183
184 def read_trie(self):
185 trie = signature_trie()
186 with io.StringIO(self.extractInput.strip()) as f:
187 for line in iter(f.readline, ""):
188 line = line.rstrip()
189 trie.add(line, line)
190 return trie
191
192 def check_patterns(self, pattern, expected):
193 trie = self.read_trie()
194 self.check_node_patterns(trie, pattern, expected)
195
196 def check_node_patterns(self, node, pattern, expected):
197 actual = list(node.get_matching_rows(pattern))
198 actual.sort()
199 self.assertEqual(expected, actual)
200
201 def test_member_pattern(self):
202 self.check_patterns("java/util/zip/ZipFile;-><clinit>()V",
203 ["Ljava/util/zip/ZipFile;-><clinit>()V"])
204
205 def test_class_pattern(self):
206 self.check_patterns("java/lang/Object", [
207 "Ljava/lang/Object;->hashCode()I",
208 "Ljava/lang/Object;->toString()Ljava/lang/String;",
209 ])
210
211 # pylint: disable=line-too-long
212 def test_nested_class_pattern(self):
213 self.check_patterns("java/lang/Character", [
214 "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
215 "Ljava/lang/Character;->serialVersionUID:J",
216 ])
217
218 def test_wildcard(self):
219 self.check_patterns("java/lang/*", [
220 "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
221 "Ljava/lang/Character;->serialVersionUID:J",
222 "Ljava/lang/Object;->hashCode()I",
223 "Ljava/lang/Object;->toString()Ljava/lang/String;",
224 "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
225 ])
226
227 def test_recursive_wildcard(self):
228 self.check_patterns("java/**", [
229 "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
230 "Ljava/lang/Character;->serialVersionUID:J",
231 "Ljava/lang/Object;->hashCode()I",
232 "Ljava/lang/Object;->toString()Ljava/lang/String;",
233 "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
234 "Ljava/util/zip/ZipFile;-><clinit>()V",
235 ])
236
Paul Duffin92532e72022-03-09 14:28:34 +0000237 def test_node_wildcard(self):
238 trie = self.read_trie()
239 node = list(trie.child_nodes())[0]
240 self.check_node_patterns(node, "**", [
241 "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
242 "Ljava/lang/Character;->serialVersionUID:J",
243 "Ljava/lang/Object;->hashCode()I",
244 "Ljava/lang/Object;->toString()Ljava/lang/String;",
245 "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
246 "Ljava/util/zip/ZipFile;-><clinit>()V",
247 ])
248
Paul Duffinb5cd5222022-02-28 19:06:49 +0000249 # pylint: enable=line-too-long
250
251
252if __name__ == "__main__":
253 unittest.main(verbosity=2)