1#!/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"""Unit tests for verify_overlaps_test.py.""" 17import io 18import unittest 19 20import verify_overlaps as vo 21 22 23class TestDetectOverlaps(unittest.TestCase): 24 25 @staticmethod 26 def read_flag_trie_from_string(csvdata): 27 with io.StringIO(csvdata) as f: 28 return vo.read_flag_trie_from_stream(f) 29 30 @staticmethod 31 def read_signature_csv_from_string_as_dict(csvdata): 32 with io.StringIO(csvdata) as f: 33 return vo.read_signature_csv_from_stream_as_dict(f) 34 35 @staticmethod 36 def extract_subset_from_monolithic_flags_as_dict_from_string( 37 monolithic, patterns): 38 with io.StringIO(patterns) as f: 39 return vo.extract_subset_from_monolithic_flags_as_dict_from_stream( 40 monolithic, f) 41 42 extractInput = """ 43Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api 44Ljava/lang/Object;->toString()Ljava/lang/String;,blocked 45Ljava/util/zip/ZipFile;-><clinit>()V,blocked 46Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;,blocked 47Ljava/lang/Character;->serialVersionUID:J,sdk 48Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V,blocked 49""" 50 51 def test_extract_subset_signature(self): 52 monolithic = self.read_flag_trie_from_string( 53 TestDetectOverlaps.extractInput) 54 55 patterns = "Ljava/lang/Object;->hashCode()I" 56 57 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string( 58 monolithic, patterns) 59 expected = { 60 "Ljava/lang/Object;->hashCode()I": { 61 None: ["public-api", "system-api", "test-api"], 62 "signature": "Ljava/lang/Object;->hashCode()I", 63 }, 64 } 65 self.assertEqual(expected, subset) 66 67 def test_extract_subset_class(self): 68 monolithic = self.read_flag_trie_from_string( 69 TestDetectOverlaps.extractInput) 70 71 patterns = "java/lang/Object" 72 73 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string( 74 monolithic, patterns) 75 expected = { 76 "Ljava/lang/Object;->hashCode()I": { 77 None: ["public-api", "system-api", "test-api"], 78 "signature": "Ljava/lang/Object;->hashCode()I", 79 }, 80 "Ljava/lang/Object;->toString()Ljava/lang/String;": { 81 None: ["blocked"], 82 "signature": "Ljava/lang/Object;->toString()Ljava/lang/String;", 83 }, 84 } 85 self.assertEqual(expected, subset) 86 87 def test_extract_subset_outer_class(self): 88 monolithic = self.read_flag_trie_from_string( 89 TestDetectOverlaps.extractInput) 90 91 patterns = "java/lang/Character" 92 93 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string( 94 monolithic, patterns) 95 expected = { 96 "Ljava/lang/Character$UnicodeScript;" 97 "->of(I)Ljava/lang/Character$UnicodeScript;": { 98 None: ["blocked"], 99 "signature": "Ljava/lang/Character$UnicodeScript;" 100 "->of(I)Ljava/lang/Character$UnicodeScript;", 101 }, 102 "Ljava/lang/Character;->serialVersionUID:J": { 103 None: ["sdk"], 104 "signature": "Ljava/lang/Character;->serialVersionUID:J", 105 }, 106 } 107 self.assertEqual(expected, subset) 108 109 def test_extract_subset_nested_class(self): 110 monolithic = self.read_flag_trie_from_string( 111 TestDetectOverlaps.extractInput) 112 113 patterns = "java/lang/Character$UnicodeScript" 114 115 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string( 116 monolithic, patterns) 117 expected = { 118 "Ljava/lang/Character$UnicodeScript;" 119 "->of(I)Ljava/lang/Character$UnicodeScript;": { 120 None: ["blocked"], 121 "signature": "Ljava/lang/Character$UnicodeScript;" 122 "->of(I)Ljava/lang/Character$UnicodeScript;", 123 }, 124 } 125 self.assertEqual(expected, subset) 126 127 def test_extract_subset_package(self): 128 monolithic = self.read_flag_trie_from_string( 129 TestDetectOverlaps.extractInput) 130 131 patterns = "java/lang/*" 132 133 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string( 134 monolithic, patterns) 135 expected = { 136 "Ljava/lang/Character$UnicodeScript;" 137 "->of(I)Ljava/lang/Character$UnicodeScript;": { 138 None: ["blocked"], 139 "signature": "Ljava/lang/Character$UnicodeScript;" 140 "->of(I)Ljava/lang/Character$UnicodeScript;", 141 }, 142 "Ljava/lang/Character;->serialVersionUID:J": { 143 None: ["sdk"], 144 "signature": "Ljava/lang/Character;->serialVersionUID:J", 145 }, 146 "Ljava/lang/Object;->hashCode()I": { 147 None: ["public-api", "system-api", "test-api"], 148 "signature": "Ljava/lang/Object;->hashCode()I", 149 }, 150 "Ljava/lang/Object;->toString()Ljava/lang/String;": { 151 None: ["blocked"], 152 "signature": "Ljava/lang/Object;->toString()Ljava/lang/String;", 153 }, 154 "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V": { 155 None: ["blocked"], 156 "signature": "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V", 157 }, 158 } 159 self.assertEqual(expected, subset) 160 161 def test_extract_subset_recursive_package(self): 162 monolithic = self.read_flag_trie_from_string( 163 TestDetectOverlaps.extractInput) 164 165 patterns = "java/**" 166 167 subset = self.extract_subset_from_monolithic_flags_as_dict_from_string( 168 monolithic, patterns) 169 expected = { 170 "Ljava/lang/Character$UnicodeScript;" 171 "->of(I)Ljava/lang/Character$UnicodeScript;": { 172 None: ["blocked"], 173 "signature": "Ljava/lang/Character$UnicodeScript;" 174 "->of(I)Ljava/lang/Character$UnicodeScript;", 175 }, 176 "Ljava/lang/Character;->serialVersionUID:J": { 177 None: ["sdk"], 178 "signature": "Ljava/lang/Character;->serialVersionUID:J", 179 }, 180 "Ljava/lang/Object;->hashCode()I": { 181 None: ["public-api", "system-api", "test-api"], 182 "signature": "Ljava/lang/Object;->hashCode()I", 183 }, 184 "Ljava/lang/Object;->toString()Ljava/lang/String;": { 185 None: ["blocked"], 186 "signature": "Ljava/lang/Object;->toString()Ljava/lang/String;", 187 }, 188 "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V": { 189 None: ["blocked"], 190 "signature": "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V", 191 }, 192 "Ljava/util/zip/ZipFile;-><clinit>()V": { 193 None: ["blocked"], 194 "signature": "Ljava/util/zip/ZipFile;-><clinit>()V", 195 }, 196 } 197 self.assertEqual(expected, subset) 198 199 def test_read_trie_duplicate(self): 200 with self.assertRaises(Exception) as context: 201 self.read_flag_trie_from_string(""" 202Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api 203Ljava/lang/Object;->hashCode()I,blocked 204""") 205 self.assertTrue("Duplicate signature: Ljava/lang/Object;->hashCode()I" 206 in str(context.exception)) 207 208 def test_read_trie_missing_member(self): 209 with self.assertRaises(Exception) as context: 210 self.read_flag_trie_from_string(""" 211Ljava/lang/Object,public-api,system-api,test-api 212""") 213 self.assertTrue( 214 "Invalid signature: Ljava/lang/Object, " 215 "does not identify a specific member" in str(context.exception)) 216 217 def test_match(self): 218 monolithic = self.read_signature_csv_from_string_as_dict(""" 219Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api 220""") 221 modular = self.read_signature_csv_from_string_as_dict(""" 222Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api 223""") 224 mismatches = vo.compare_signature_flags(monolithic, modular, 225 ["blocked"]) 226 expected = [] 227 self.assertEqual(expected, mismatches) 228 229 def test_mismatch_overlapping_flags(self): 230 monolithic = self.read_signature_csv_from_string_as_dict(""" 231Ljava/lang/Object;->toString()Ljava/lang/String;,public-api 232""") 233 modular = self.read_signature_csv_from_string_as_dict(""" 234Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api 235""") 236 mismatches = vo.compare_signature_flags(monolithic, modular, 237 ["blocked"]) 238 expected = [ 239 ( 240 "Ljava/lang/Object;->toString()Ljava/lang/String;", 241 ["public-api", "system-api", "test-api"], 242 ["public-api"], 243 ), 244 ] 245 self.assertEqual(expected, mismatches) 246 247 def test_mismatch_monolithic_blocked(self): 248 monolithic = self.read_signature_csv_from_string_as_dict(""" 249Ljava/lang/Object;->toString()Ljava/lang/String;,blocked 250""") 251 modular = self.read_signature_csv_from_string_as_dict(""" 252Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api 253""") 254 mismatches = vo.compare_signature_flags(monolithic, modular, 255 ["blocked"]) 256 expected = [ 257 ( 258 "Ljava/lang/Object;->toString()Ljava/lang/String;", 259 ["public-api", "system-api", "test-api"], 260 ["blocked"], 261 ), 262 ] 263 self.assertEqual(expected, mismatches) 264 265 def test_mismatch_modular_blocked(self): 266 monolithic = self.read_signature_csv_from_string_as_dict(""" 267Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api 268""") 269 modular = self.read_signature_csv_from_string_as_dict(""" 270Ljava/lang/Object;->toString()Ljava/lang/String;,blocked 271""") 272 mismatches = vo.compare_signature_flags(monolithic, modular, 273 ["blocked"]) 274 expected = [ 275 ( 276 "Ljava/lang/Object;->toString()Ljava/lang/String;", 277 ["blocked"], 278 ["public-api", "system-api", "test-api"], 279 ), 280 ] 281 self.assertEqual(expected, mismatches) 282 283 def test_match_treat_missing_from_modular_as_blocked(self): 284 monolithic = self.read_signature_csv_from_string_as_dict("") 285 modular = self.read_signature_csv_from_string_as_dict(""" 286Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api 287""") 288 mismatches = vo.compare_signature_flags(monolithic, modular, 289 ["blocked"]) 290 expected = [ 291 ( 292 "Ljava/lang/Object;->toString()Ljava/lang/String;", 293 ["public-api", "system-api", "test-api"], 294 [], 295 ), 296 ] 297 self.assertEqual(expected, mismatches) 298 299 def test_mismatch_treat_missing_from_modular_as_blocked(self): 300 monolithic = self.read_signature_csv_from_string_as_dict(""" 301Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api 302""") 303 modular = {} 304 mismatches = vo.compare_signature_flags(monolithic, modular, 305 ["blocked"]) 306 expected = [ 307 ( 308 "Ljava/lang/Object;->hashCode()I", 309 ["blocked"], 310 ["public-api", "system-api", "test-api"], 311 ), 312 ] 313 self.assertEqual(expected, mismatches) 314 315 def test_blocked_missing_from_modular(self): 316 monolithic = self.read_signature_csv_from_string_as_dict(""" 317Ljava/lang/Object;->hashCode()I,blocked 318""") 319 modular = {} 320 mismatches = vo.compare_signature_flags(monolithic, modular, 321 ["blocked"]) 322 expected = [] 323 self.assertEqual(expected, mismatches) 324 325 def test_match_treat_missing_from_modular_as_empty(self): 326 monolithic = self.read_signature_csv_from_string_as_dict("") 327 modular = self.read_signature_csv_from_string_as_dict(""" 328Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api 329""") 330 mismatches = vo.compare_signature_flags(monolithic, modular, []) 331 expected = [ 332 ( 333 "Ljava/lang/Object;->toString()Ljava/lang/String;", 334 ["public-api", "system-api", "test-api"], 335 [], 336 ), 337 ] 338 self.assertEqual(expected, mismatches) 339 340 def test_mismatch_treat_missing_from_modular_as_empty(self): 341 monolithic = self.read_signature_csv_from_string_as_dict(""" 342Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api 343""") 344 modular = {} 345 mismatches = vo.compare_signature_flags(monolithic, modular, []) 346 expected = [ 347 ( 348 "Ljava/lang/Object;->hashCode()I", 349 [], 350 ["public-api", "system-api", "test-api"], 351 ), 352 ] 353 self.assertEqual(expected, mismatches) 354 355 def test_empty_missing_from_modular(self): 356 monolithic = self.read_signature_csv_from_string_as_dict(""" 357Ljava/lang/Object;->hashCode()I 358""") 359 modular = {} 360 mismatches = vo.compare_signature_flags(monolithic, modular, []) 361 expected = [] 362 self.assertEqual(expected, mismatches) 363 364 365if __name__ == "__main__": 366 unittest.main(verbosity=2) 367