1#!/usr/bin/env python3 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"""Tests for dependency_analysis.py.""" 17 18import dependency_analysis 19import queryview_xml 20import soong_module_json 21import unittest 22 23 24class DependencyAnalysisTest(unittest.TestCase): 25 26 def test_visit_json_module_graph_post_order_visits_all_in_post_order(self): 27 graph = [ 28 soong_module_json.make_module('q', 'module', [ 29 soong_module_json.make_dep('a'), 30 soong_module_json.make_dep('b'), 31 ]), 32 soong_module_json.make_module('a', 'module', [ 33 soong_module_json.make_dep('b'), 34 soong_module_json.make_dep('c'), 35 ]), 36 soong_module_json.make_module('b', 'module', [ 37 soong_module_json.make_dep('d'), 38 ]), 39 soong_module_json.make_module('c', 'module', [ 40 soong_module_json.make_dep('e'), 41 ]), 42 soong_module_json.make_module('d', 'module', []), 43 soong_module_json.make_module('e', 'module', []), 44 ] 45 46 def only_a(json): 47 return json['Name'] == 'a' 48 49 visited_modules = [] 50 51 def visit(module, _): 52 visited_modules.append(module['Name']) 53 54 dependency_analysis.visit_json_module_graph_post_order( 55 graph, set(), False, only_a, visit) 56 57 expected_visited = ['d', 'b', 'e', 'c', 'a'] 58 self.assertListEqual(visited_modules, expected_visited) 59 60 def test_visit_json_module_graph_post_order_skips_ignored_by_name_and_transitive( 61 self): 62 graph = [ 63 soong_module_json.make_module('a', 'module', [ 64 soong_module_json.make_dep('b'), 65 soong_module_json.make_dep('c'), 66 ]), 67 soong_module_json.make_module('b', 'module', [ 68 soong_module_json.make_dep('d'), 69 ]), 70 soong_module_json.make_module('c', 'module', [ 71 soong_module_json.make_dep('e'), 72 ]), 73 soong_module_json.make_module('d', 'module', []), 74 soong_module_json.make_module('e', 'module', []), 75 ] 76 77 def only_a(json): 78 return json['Name'] == 'a' 79 80 visited_modules = [] 81 82 def visit(module, _): 83 visited_modules.append(module['Name']) 84 85 dependency_analysis.visit_json_module_graph_post_order( 86 graph, set('b'), False, only_a, visit) 87 88 expected_visited = ['e', 'c', 'a'] 89 self.assertListEqual(visited_modules, expected_visited) 90 91 def test_visit_json_module_graph_post_order_skips_defaults_and_transitive( 92 self): 93 graph = [ 94 soong_module_json.make_module('a', 'module', [ 95 soong_module_json.make_dep('b'), 96 soong_module_json.make_dep('c'), 97 ]), 98 soong_module_json.make_module('b', 'module_defaults', [ 99 soong_module_json.make_dep('d'), 100 ]), 101 soong_module_json.make_module('c', 'module', [ 102 soong_module_json.make_dep('e'), 103 ]), 104 soong_module_json.make_module('d', 'module', []), 105 soong_module_json.make_module('e', 'module', []), 106 ] 107 108 def only_a(json): 109 return json['Name'] == 'a' 110 111 visited_modules = [] 112 113 def visit(module, _): 114 visited_modules.append(module['Name']) 115 116 dependency_analysis.visit_json_module_graph_post_order( 117 graph, set(), False, only_a, visit) 118 119 expected_visited = ['e', 'c', 'a'] 120 self.assertListEqual(visited_modules, expected_visited) 121 122 def test_visit_json_module_graph_post_order_skips_windows_and_transitive( 123 self): 124 windows_variation = soong_module_json.make_variation('os', 'windows') 125 graph = [ 126 soong_module_json.make_module('a', 'module', [ 127 soong_module_json.make_dep('b', variations=[windows_variation]), 128 soong_module_json.make_dep('c'), 129 ]), 130 soong_module_json.make_module( 131 'b', 132 'module', 133 [ 134 soong_module_json.make_dep('d'), 135 ], 136 variations=[windows_variation], 137 ), 138 soong_module_json.make_module('c', 'module', [ 139 soong_module_json.make_dep('e'), 140 ]), 141 soong_module_json.make_module('d', 'module', []), 142 soong_module_json.make_module('e', 'module', []), 143 ] 144 145 def only_a(json): 146 return json['Name'] == 'a' 147 148 visited_modules = [] 149 150 def visit(module, _): 151 visited_modules.append(module['Name']) 152 153 dependency_analysis.visit_json_module_graph_post_order( 154 graph, set(), False, only_a, visit) 155 156 expected_visited = ['e', 'c', 'a'] 157 self.assertListEqual(visited_modules, expected_visited) 158 159 def test_visit_json_module_graph_post_order_skips_prebuilt_tag_deps(self): 160 graph = [ 161 soong_module_json.make_module('a', 'module', [ 162 soong_module_json.make_dep( 163 'b', 'android.prebuiltDependencyTag {BaseDependencyTag:{}}'), 164 soong_module_json.make_dep('c'), 165 ]), 166 soong_module_json.make_module('b', 'module', [ 167 soong_module_json.make_dep('d'), 168 ]), 169 soong_module_json.make_module('c', 'module', [ 170 soong_module_json.make_dep('e'), 171 ]), 172 soong_module_json.make_module('d', 'module', []), 173 soong_module_json.make_module('e', 'module', []), 174 ] 175 176 def only_a(json): 177 return json['Name'] == 'a' 178 179 visited_modules = [] 180 181 def visit(module, _): 182 visited_modules.append(module['Name']) 183 184 dependency_analysis.visit_json_module_graph_post_order( 185 graph, set(), False, only_a, visit) 186 187 expected_visited = ['e', 'c', 'a'] 188 self.assertListEqual(visited_modules, expected_visited) 189 190 def test_visit_json_module_graph_post_order_no_infinite_loop_for_self_dep( 191 self): 192 graph = [ 193 soong_module_json.make_module('a', 'module', 194 [soong_module_json.make_dep('a')]), 195 ] 196 197 def only_a(json): 198 return json['Name'] == 'a' 199 200 visited_modules = [] 201 202 def visit(module, _): 203 visited_modules.append(module['Name']) 204 205 dependency_analysis.visit_json_module_graph_post_order( 206 graph, set(), False, only_a, visit) 207 208 expected_visited = ['a'] 209 self.assertListEqual(visited_modules, expected_visited) 210 211 def test_visit_json_module_graph_post_order_visits_all_variants(self): 212 graph = [ 213 soong_module_json.make_module( 214 'a', 215 'module', 216 [ 217 soong_module_json.make_dep('b'), 218 ], 219 variations=[soong_module_json.make_variation('m', '1')], 220 ), 221 soong_module_json.make_module( 222 'a', 223 'module', 224 [ 225 soong_module_json.make_dep('c'), 226 ], 227 variations=[soong_module_json.make_variation('m', '2')], 228 ), 229 soong_module_json.make_module('b', 'module', [ 230 soong_module_json.make_dep('d'), 231 ]), 232 soong_module_json.make_module('c', 'module', [ 233 soong_module_json.make_dep('e'), 234 ]), 235 soong_module_json.make_module('d', 'module', []), 236 soong_module_json.make_module('e', 'module', []), 237 ] 238 239 def only_a(json): 240 return json['Name'] == 'a' 241 242 visited_modules = [] 243 244 def visit(module, _): 245 visited_modules.append(module['Name']) 246 247 dependency_analysis.visit_json_module_graph_post_order( 248 graph, set(), False, only_a, visit) 249 250 expected_visited = ['d', 'b', 'a', 'e', 'c', 'a'] 251 self.assertListEqual(visited_modules, expected_visited) 252 253 def test_visit_json_module_skips_filegroup_with_src_same_as_name(self): 254 graph = [ 255 soong_module_json.make_module( 256 'a', 257 'filegroup', 258 [ 259 soong_module_json.make_dep('b'), 260 ], 261 json_props=[ 262 soong_module_json.make_property( 263 name='Srcs', 264 values=['other_file'], 265 ), 266 ], 267 ), 268 soong_module_json.make_module( 269 'b', 270 'filegroup', 271 json_props=[ 272 soong_module_json.make_property( 273 name='Srcs', 274 values=['b'], 275 ), 276 ], 277 ), 278 ] 279 280 def only_a(json): 281 return json['Name'] == 'a' 282 283 visited_modules = [] 284 285 def visit(module, _): 286 visited_modules.append(module['Name']) 287 288 dependency_analysis.visit_json_module_graph_post_order( 289 graph, set(), False, only_a, visit) 290 291 expected_visited = ['a'] 292 self.assertListEqual(visited_modules, expected_visited) 293 294 def test_visit_json_module_graph_post_order_include_created_by(self): 295 graph = [ 296 soong_module_json.make_module('a', 'module', [ 297 soong_module_json.make_dep('b'), 298 soong_module_json.make_dep('c'), 299 ]), 300 soong_module_json.make_module('b', 'module', created_by='d'), 301 soong_module_json.make_module('c', 'module', [ 302 soong_module_json.make_dep('e'), 303 ]), 304 soong_module_json.make_module('d', 'module', []), 305 soong_module_json.make_module('e', 'module', []), 306 ] 307 308 def only_a(json): 309 return json['Name'] == 'a' 310 311 visited_modules = [] 312 313 def visit(module, _): 314 visited_modules.append(module['Name']) 315 316 dependency_analysis.visit_json_module_graph_post_order( 317 graph, set(), False, only_a, visit) 318 319 expected_visited = ['d', 'b', 'e', 'c', 'a'] 320 self.assertListEqual(visited_modules, expected_visited) 321 322 def test_visit_queryview_xml_module_graph_post_order_visits_all(self): 323 graph = queryview_xml.make_graph([ 324 queryview_xml.make_module( 325 '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), 326 queryview_xml.make_module( 327 '//pkg:b', 'b', 'module', dep_names=['//pkg:d']), 328 queryview_xml.make_module( 329 '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), 330 queryview_xml.make_module('//pkg:d', 'd', 'module'), 331 queryview_xml.make_module('//pkg:e', 'e', 'module'), 332 ]) 333 334 def only_a(module): 335 return module.name == 'a' 336 337 visited_modules = [] 338 339 def visit(module, _): 340 visited_modules.append(module.name) 341 342 dependency_analysis.visit_queryview_xml_module_graph_post_order( 343 graph, set(), only_a, visit) 344 345 expected_visited = ['d', 'b', 'e', 'c', 'a'] 346 self.assertListEqual(visited_modules, expected_visited) 347 348 def test_visit_queryview_xml_module_graph_post_order_skips_ignore_by_name( 349 self): 350 graph = queryview_xml.make_graph([ 351 queryview_xml.make_module( 352 '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), 353 queryview_xml.make_module( 354 '//pkg:b', 'b', 'module', dep_names=['//pkg:d']), 355 queryview_xml.make_module( 356 '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), 357 queryview_xml.make_module('//pkg:d', 'd', 'module'), 358 queryview_xml.make_module('//pkg:e', 'e', 'module'), 359 ]) 360 361 def only_a(module): 362 return module.name == 'a' 363 364 visited_modules = [] 365 366 def visit(module, _): 367 visited_modules.append(module.name) 368 369 dependency_analysis.visit_queryview_xml_module_graph_post_order( 370 graph, set('b'), only_a, visit) 371 372 expected_visited = ['e', 'c', 'a'] 373 self.assertListEqual(visited_modules, expected_visited) 374 375 def test_visit_queryview_xml_module_graph_post_order_skips_default(self): 376 graph = queryview_xml.make_graph([ 377 queryview_xml.make_module( 378 '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), 379 queryview_xml.make_module( 380 '//pkg:b', 'b', 'module_defaults', dep_names=['//pkg:d']), 381 queryview_xml.make_module( 382 '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), 383 queryview_xml.make_module('//pkg:d', 'd', 'module'), 384 queryview_xml.make_module('//pkg:e', 'e', 'module'), 385 ]) 386 387 def only_a(module): 388 return module.name == 'a' 389 390 visited_modules = [] 391 392 def visit(module, _): 393 visited_modules.append(module.name) 394 395 dependency_analysis.visit_queryview_xml_module_graph_post_order( 396 graph, set(), only_a, visit) 397 398 expected_visited = ['e', 'c', 'a'] 399 self.assertListEqual(visited_modules, expected_visited) 400 401 def test_visit_queryview_xml_module_graph_post_order_skips_cc_prebuilt(self): 402 graph = queryview_xml.make_graph([ 403 queryview_xml.make_module( 404 '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), 405 queryview_xml.make_module( 406 '//pkg:b', 'b', 'cc_prebuilt_library', dep_names=['//pkg:d']), 407 queryview_xml.make_module( 408 '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), 409 queryview_xml.make_module('//pkg:d', 'd', 'module'), 410 queryview_xml.make_module('//pkg:e', 'e', 'module'), 411 ]) 412 413 def only_a(module): 414 return module.name == 'a' 415 416 visited_modules = [] 417 418 def visit(module, _): 419 visited_modules.append(module.name) 420 421 dependency_analysis.visit_queryview_xml_module_graph_post_order( 422 graph, set(), only_a, visit) 423 424 expected_visited = ['e', 'c', 'a'] 425 self.assertListEqual(visited_modules, expected_visited) 426 427 def test_visit_queryview_xml_module_graph_post_order_skips_filegroup_duplicate_name( 428 self): 429 graph = queryview_xml.make_graph([ 430 queryview_xml.make_module( 431 '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), 432 queryview_xml.make_module( 433 '//pkg:b', 'b', 'filegroup', dep_names=['//pkg:d'], srcs=['b']), 434 queryview_xml.make_module( 435 '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), 436 queryview_xml.make_module('//pkg:d', 'd', 'module'), 437 queryview_xml.make_module('//pkg:e', 'e', 'module'), 438 ]) 439 440 def only_a(module): 441 return module.name == 'a' 442 443 visited_modules = [] 444 445 def visit(module, _): 446 visited_modules.append(module.name) 447 448 dependency_analysis.visit_queryview_xml_module_graph_post_order( 449 graph, set(), only_a, visit) 450 451 expected_visited = ['e', 'c', 'a'] 452 self.assertListEqual(visited_modules, expected_visited) 453 454 def test_visit_queryview_xml_module_graph_post_order_skips_windows(self): 455 graph = queryview_xml.make_graph([ 456 queryview_xml.make_module( 457 '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), 458 queryview_xml.make_module( 459 '//pkg:b', 460 'b', 461 'module', 462 dep_names=['//pkg:d'], 463 variant='windows-x86'), 464 queryview_xml.make_module( 465 '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), 466 queryview_xml.make_module('//pkg:d', 'd', 'module'), 467 queryview_xml.make_module('//pkg:e', 'e', 'module'), 468 ]) 469 470 def only_a(module): 471 return module.name == 'a' 472 473 visited_modules = [] 474 475 def visit(module, _): 476 visited_modules.append(module.name) 477 478 dependency_analysis.visit_queryview_xml_module_graph_post_order( 479 graph, set(), only_a, visit) 480 481 expected_visited = ['e', 'c', 'a'] 482 self.assertListEqual(visited_modules, expected_visited) 483 484 def test_visit_queryview_xml_module_graph_post_order_self_dep_no_infinite_loop( 485 self): 486 graph = queryview_xml.make_graph([ 487 queryview_xml.make_module( 488 '//pkg:a', 489 'a', 490 'module', 491 dep_names=['//pkg:b--variant1', '//pkg:c']), 492 queryview_xml.make_module( 493 '//pkg:b--variant1', 494 'b', 495 'module', 496 variant='variant1', 497 dep_names=['//pkg:b--variant2']), 498 queryview_xml.make_module( 499 '//pkg:b--variant2', 500 'b', 501 'module', 502 variant='variant2', 503 dep_names=['//pkg:d']), 504 queryview_xml.make_module( 505 '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), 506 queryview_xml.make_module('//pkg:d', 'd', 'module'), 507 queryview_xml.make_module('//pkg:e', 'e', 'module'), 508 ]) 509 510 def only_a(module): 511 return module.name == 'a' 512 513 visited_modules = [] 514 515 def visit(module, _): 516 visited_modules.append(module.name) 517 518 dependency_analysis.visit_queryview_xml_module_graph_post_order( 519 graph, set(), only_a, visit) 520 521 expected_visited = ['d', 'b', 'b', 'e', 'c', 'a'] 522 self.assertListEqual(visited_modules, expected_visited) 523 524 def test_visit_queryview_xml_module_graph_post_order_skips_prebuilt_with_same_name( 525 self): 526 graph = queryview_xml.make_graph([ 527 queryview_xml.make_module( 528 '//pkg:a', 529 'a', 530 'module', 531 dep_names=['//other_pkg:prebuilt_a', '//pkg:b', '//pkg:c']), 532 queryview_xml.make_module('//other_pkg:prebuilt_a', 'prebuilt_a', 533 'prebuilt_module'), 534 queryview_xml.make_module( 535 '//pkg:b', 'b', 'module', dep_names=['//pkg:d']), 536 queryview_xml.make_module( 537 '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), 538 queryview_xml.make_module('//pkg:d', 'd', 'module'), 539 queryview_xml.make_module('//pkg:e', 'e', 'module'), 540 ]) 541 542 def only_a(module): 543 return module.name == 'a' 544 545 visited_modules = [] 546 547 def visit(module, _): 548 visited_modules.append(module.name) 549 550 dependency_analysis.visit_queryview_xml_module_graph_post_order( 551 graph, set(), only_a, visit) 552 553 expected_visited = ['d', 'b', 'e', 'c', 'a'] 554 self.assertListEqual(visited_modules, expected_visited) 555 556 557if __name__ == '__main__': 558 unittest.main() 559