blob: 747725458f03ac4109eca24170b5e9fa889aa46c [file] [log] [blame]
Paul Duffin428c6512021-07-21 15:33:22 +01001#!/usr/bin/env python
2#
3# Copyright (C) 2021 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
17"""Unit tests for verify_overlaps_test.py."""
18import io
19import unittest
20
21from verify_overlaps import *
22
Paul Duffinc11f6672021-07-20 00:04:21 +010023class TestSignatureToElements(unittest.TestCase):
24
25 def signatureToElements(self, signature):
26 return InteriorNode().signatureToElements(signature)
27
28 def test_signatureToElements_1(self):
29 expected = [
30 'package:java',
31 'package:lang',
32 'class:ProcessBuilder',
33 'class:Redirect',
34 'class:1',
35 'member:<init>()V',
36 ]
37 self.assertEqual(expected, self.signatureToElements(
38 "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V"))
39
40 def test_signatureToElements_2(self):
41 expected = [
42 'package:java',
43 'package:lang',
44 'class:Object',
45 'member:hashCode()I',
46 ]
47 self.assertEqual(expected, self.signatureToElements(
48 "Ljava/lang/Object;->hashCode()I"))
49
50 def test_signatureToElements_3(self):
51 expected = [
52 'package:java',
53 'package:lang',
54 'class:CharSequence',
55 'class:',
56 'class:ExternalSyntheticLambda0',
57 'member:<init>(Ljava/lang/CharSequence;)V',
58 ]
59 self.assertEqual(expected, self.signatureToElements(
60 "Ljava/lang/CharSequence$$ExternalSyntheticLambda0;"
61 "-><init>(Ljava/lang/CharSequence;)V"))
62
Paul Duffin428c6512021-07-21 15:33:22 +010063class TestDetectOverlaps(unittest.TestCase):
64
Paul Duffinc11f6672021-07-20 00:04:21 +010065 def read_flag_trie_from_string(self, csv):
66 with io.StringIO(csv) as f:
67 return read_flag_trie_from_stream(f)
68
Paul Duffin428c6512021-07-21 15:33:22 +010069 def read_signature_csv_from_string_as_dict(self, csv):
70 with io.StringIO(csv) as f:
71 return read_signature_csv_from_stream_as_dict(f)
72
Paul Duffin67b9d612021-07-21 17:38:47 +010073 def extract_subset_from_monolithic_flags_as_dict_from_string(self, monolithic, patterns):
74 with io.StringIO(patterns) as f:
75 return extract_subset_from_monolithic_flags_as_dict_from_stream(monolithic, f)
76
Paul Duffin53a76072021-07-21 17:27:09 +010077 extractInput = '''
78Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
79Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
Paul Duffinc11f6672021-07-20 00:04:21 +010080Ljava/util/zip/ZipFile;-><clinit>()V,blocked
81Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;,blocked
82Ljava/lang/Character;->serialVersionUID:J,sdk
83Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V,blocked
Paul Duffin53a76072021-07-21 17:27:09 +010084'''
85
Paul Duffinc11f6672021-07-20 00:04:21 +010086 def test_extract_subset_signature(self):
87 monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
Paul Duffin67b9d612021-07-21 17:38:47 +010088
89 patterns = 'Ljava/lang/Object;->hashCode()I'
90
91 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
Paul Duffin53a76072021-07-21 17:27:09 +010092 expected = {
93 'Ljava/lang/Object;->hashCode()I': {
94 None: ['public-api', 'system-api', 'test-api'],
95 'signature': 'Ljava/lang/Object;->hashCode()I',
96 },
97 }
98 self.assertEqual(expected, subset)
99
Paul Duffinc11f6672021-07-20 00:04:21 +0100100 def test_extract_subset_class(self):
101 monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
102
103 patterns = 'java/lang/Object'
104
105 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
106 expected = {
107 'Ljava/lang/Object;->hashCode()I': {
108 None: ['public-api', 'system-api', 'test-api'],
109 'signature': 'Ljava/lang/Object;->hashCode()I',
110 },
111 'Ljava/lang/Object;->toString()Ljava/lang/String;': {
112 None: ['blocked'],
113 'signature': 'Ljava/lang/Object;->toString()Ljava/lang/String;',
114 },
115 }
116 self.assertEqual(expected, subset)
117
118 def test_extract_subset_outer_class(self):
119 monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
120
121 patterns = 'java/lang/Character'
122
123 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
124 expected = {
125 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
126 None: ['blocked'],
127 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
128 },
129 'Ljava/lang/Character;->serialVersionUID:J': {
130 None: ['sdk'],
131 'signature': 'Ljava/lang/Character;->serialVersionUID:J',
132 },
133 }
134 self.assertEqual(expected, subset)
135
136 def test_extract_subset_nested_class(self):
137 monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
138
139 patterns = 'java/lang/Character$UnicodeScript'
140
141 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
142 expected = {
143 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
144 None: ['blocked'],
145 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
146 },
147 }
148 self.assertEqual(expected, subset)
149
150 def test_extract_subset_package(self):
151 monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
152
153 patterns = 'java/lang/*'
154
155 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
156 expected = {
157 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
158 None: ['blocked'],
159 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
160 },
161 'Ljava/lang/Character;->serialVersionUID:J': {
162 None: ['sdk'],
163 'signature': 'Ljava/lang/Character;->serialVersionUID:J',
164 },
165 'Ljava/lang/Object;->hashCode()I': {
166 None: ['public-api', 'system-api', 'test-api'],
167 'signature': 'Ljava/lang/Object;->hashCode()I',
168 },
169 'Ljava/lang/Object;->toString()Ljava/lang/String;': {
170 None: ['blocked'],
171 'signature': 'Ljava/lang/Object;->toString()Ljava/lang/String;',
172 },
173 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V': {
174 None: ['blocked'],
175 'signature': 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V',
176 },
177 }
178 self.assertEqual(expected, subset)
179
180 def test_extract_subset_recursive_package(self):
181 monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
182
183 patterns = 'java/**'
184
185 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
186 expected = {
187 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
188 None: ['blocked'],
189 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
190 },
191 'Ljava/lang/Character;->serialVersionUID:J': {
192 None: ['sdk'],
193 'signature': 'Ljava/lang/Character;->serialVersionUID:J',
194 },
195 'Ljava/lang/Object;->hashCode()I': {
196 None: ['public-api', 'system-api', 'test-api'],
197 'signature': 'Ljava/lang/Object;->hashCode()I',
198 },
199 'Ljava/lang/Object;->toString()Ljava/lang/String;': {
200 None: ['blocked'],
201 'signature': 'Ljava/lang/Object;->toString()Ljava/lang/String;',
202 },
203 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V': {
204 None: ['blocked'],
205 'signature': 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V',
206 },
207 'Ljava/util/zip/ZipFile;-><clinit>()V': {
208 None: ['blocked'],
209 'signature': 'Ljava/util/zip/ZipFile;-><clinit>()V',
210 },
211 }
212 self.assertEqual(expected, subset)
213
214 def test_extract_subset_invalid_pattern_wildcard_and_member(self):
215 monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
216
217 patterns = 'Ljava/lang/*;->hashCode()I'
218
219 with self.assertRaises(Exception) as context:
220 self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
221 self.assertTrue("contains wildcard * and member signature hashCode()I" in str(context.exception))
222
223 def test_read_trie_duplicate(self):
224 with self.assertRaises(Exception) as context:
225 self.read_flag_trie_from_string('''
226Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
227Ljava/lang/Object;->hashCode()I,blocked
228''')
229 self.assertTrue("Duplicate signature: Ljava/lang/Object;->hashCode()I" in str(context.exception))
230
231 def test_read_trie_missing_member(self):
232 with self.assertRaises(Exception) as context:
233 self.read_flag_trie_from_string('''
234Ljava/lang/Object,public-api,system-api,test-api
235''')
236 self.assertTrue("Invalid signature: Ljava/lang/Object, does not identify a specific member" in str(context.exception))
237
Paul Duffin428c6512021-07-21 15:33:22 +0100238 def test_match(self):
239 monolithic = self.read_signature_csv_from_string_as_dict('''
240Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
Paul Duffin428c6512021-07-21 15:33:22 +0100241''')
242 modular = self.read_signature_csv_from_string_as_dict('''
243Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
244''')
245 mismatches = compare_signature_flags(monolithic, modular)
246 expected = []
247 self.assertEqual(expected, mismatches)
248
249 def test_mismatch_overlapping_flags(self):
250 monolithic = self.read_signature_csv_from_string_as_dict('''
251Ljava/lang/Object;->toString()Ljava/lang/String;,public-api
252''')
253 modular = self.read_signature_csv_from_string_as_dict('''
254Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
255''')
256 mismatches = compare_signature_flags(monolithic, modular)
257 expected = [
258 (
259 'Ljava/lang/Object;->toString()Ljava/lang/String;',
260 ['public-api', 'system-api', 'test-api'],
261 ['public-api'],
262 ),
263 ]
264 self.assertEqual(expected, mismatches)
265
266
267 def test_mismatch_monolithic_blocked(self):
268 monolithic = self.read_signature_csv_from_string_as_dict('''
Paul Duffin428c6512021-07-21 15:33:22 +0100269Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
270''')
271 modular = self.read_signature_csv_from_string_as_dict('''
272Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
273''')
274 mismatches = compare_signature_flags(monolithic, modular)
275 expected = [
276 (
277 'Ljava/lang/Object;->toString()Ljava/lang/String;',
278 ['public-api', 'system-api', 'test-api'],
279 ['blocked'],
280 ),
281 ]
282 self.assertEqual(expected, mismatches)
283
284 def test_mismatch_modular_blocked(self):
285 monolithic = self.read_signature_csv_from_string_as_dict('''
Paul Duffin428c6512021-07-21 15:33:22 +0100286Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
287''')
288 modular = self.read_signature_csv_from_string_as_dict('''
289Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
290''')
291 mismatches = compare_signature_flags(monolithic, modular)
292 expected = [
293 (
294 'Ljava/lang/Object;->toString()Ljava/lang/String;',
295 ['blocked'],
296 ['public-api', 'system-api', 'test-api'],
297 ),
298 ]
299 self.assertEqual(expected, mismatches)
300
301 def test_missing_from_monolithic(self):
Paul Duffin53a76072021-07-21 17:27:09 +0100302 monolithic = self.read_signature_csv_from_string_as_dict('')
Paul Duffin428c6512021-07-21 15:33:22 +0100303 modular = self.read_signature_csv_from_string_as_dict('''
304Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
305''')
306 mismatches = compare_signature_flags(monolithic, modular)
307 expected = [
308 (
309 'Ljava/lang/Object;->toString()Ljava/lang/String;',
310 ['public-api', 'system-api', 'test-api'],
311 [],
312 ),
313 ]
314 self.assertEqual(expected, mismatches)
315
316 def test_missing_from_modular(self):
Paul Duffin428c6512021-07-21 15:33:22 +0100317 monolithic = self.read_signature_csv_from_string_as_dict('''
318Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
319''')
320 modular = {}
321 mismatches = compare_signature_flags(monolithic, modular)
Paul Duffin53a76072021-07-21 17:27:09 +0100322 expected = [
323 (
324 'Ljava/lang/Object;->hashCode()I',
325 [],
326 ['public-api', 'system-api', 'test-api'],
327 ),
328 ]
Paul Duffin428c6512021-07-21 15:33:22 +0100329 self.assertEqual(expected, mismatches)
330
331 def test_blocked_missing_from_modular(self):
Paul Duffin428c6512021-07-21 15:33:22 +0100332 monolithic = self.read_signature_csv_from_string_as_dict('''
333Ljava/lang/Object;->hashCode()I,blocked
334''')
335 modular = {}
336 mismatches = compare_signature_flags(monolithic, modular)
Paul Duffin53a76072021-07-21 17:27:09 +0100337 expected = [
338 (
339 'Ljava/lang/Object;->hashCode()I',
340 [],
341 ['blocked'],
342 ),
343 ]
Paul Duffin428c6512021-07-21 15:33:22 +0100344 self.assertEqual(expected, mismatches)
345
346if __name__ == '__main__':
347 unittest.main(verbosity=2)