#!/usr/bin/env python3 # Copyright (C) 2022 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tests for dependency_analysis.py.""" import dependency_analysis import queryview_xml import soong_module_json import unittest class DependencyAnalysisTest(unittest.TestCase): def test_visit_json_module_graph_post_order_visits_all_in_post_order(self): graph = [ soong_module_json.make_module('q', 'module', [ soong_module_json.make_dep('a'), soong_module_json.make_dep('b'), ]), soong_module_json.make_module('a', 'module', [ soong_module_json.make_dep('b'), soong_module_json.make_dep('c'), ]), soong_module_json.make_module('b', 'module', [ soong_module_json.make_dep('d'), ]), soong_module_json.make_module('c', 'module', [ soong_module_json.make_dep('e'), ]), soong_module_json.make_module('d', 'module', []), soong_module_json.make_module('e', 'module', []), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set(), False, only_a, visit) expected_visited = ['d', 'b', 'e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_json_module_graph_post_order_skips_ignored_by_name_and_transitive( self): graph = [ soong_module_json.make_module('a', 'module', [ soong_module_json.make_dep('b'), soong_module_json.make_dep('c'), ]), soong_module_json.make_module('b', 'module', [ soong_module_json.make_dep('d'), ]), soong_module_json.make_module('c', 'module', [ soong_module_json.make_dep('e'), ]), soong_module_json.make_module('d', 'module', []), soong_module_json.make_module('e', 'module', []), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set('b'), False, only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_json_module_graph_post_order_skips_defaults_and_transitive( self): graph = [ soong_module_json.make_module('a', 'module', [ soong_module_json.make_dep('b'), soong_module_json.make_dep('c'), ]), soong_module_json.make_module('b', 'module_defaults', [ soong_module_json.make_dep('d'), ]), soong_module_json.make_module('c', 'module', [ soong_module_json.make_dep('e'), ]), soong_module_json.make_module('d', 'module', []), soong_module_json.make_module('e', 'module', []), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set(), False, only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_json_module_graph_post_order_skips_windows_and_transitive( self): windows_variation = soong_module_json.make_variation('os', 'windows') graph = [ soong_module_json.make_module('a', 'module', [ soong_module_json.make_dep('b', variations=[windows_variation]), soong_module_json.make_dep('c'), ]), soong_module_json.make_module( 'b', 'module', [ soong_module_json.make_dep('d'), ], variations=[windows_variation], ), soong_module_json.make_module('c', 'module', [ soong_module_json.make_dep('e'), ]), soong_module_json.make_module('d', 'module', []), soong_module_json.make_module('e', 'module', []), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set(), False, only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_json_module_graph_post_order_skips_prebuilt_tag_deps(self): graph = [ soong_module_json.make_module('a', 'module', [ soong_module_json.make_dep( 'b', 'android.prebuiltDependencyTag {BaseDependencyTag:{}}'), soong_module_json.make_dep('c'), ]), soong_module_json.make_module('b', 'module', [ soong_module_json.make_dep('d'), ]), soong_module_json.make_module('c', 'module', [ soong_module_json.make_dep('e'), ]), soong_module_json.make_module('d', 'module', []), soong_module_json.make_module('e', 'module', []), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set(), False, only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_json_module_graph_post_order_no_infinite_loop_for_self_dep( self): graph = [ soong_module_json.make_module('a', 'module', [soong_module_json.make_dep('a')]), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set(), False, only_a, visit) expected_visited = ['a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_json_module_graph_post_order_visits_all_variants(self): graph = [ soong_module_json.make_module( 'a', 'module', [ soong_module_json.make_dep('b'), ], variations=[soong_module_json.make_variation('m', '1')], ), soong_module_json.make_module( 'a', 'module', [ soong_module_json.make_dep('c'), ], variations=[soong_module_json.make_variation('m', '2')], ), soong_module_json.make_module('b', 'module', [ soong_module_json.make_dep('d'), ]), soong_module_json.make_module('c', 'module', [ soong_module_json.make_dep('e'), ]), soong_module_json.make_module('d', 'module', []), soong_module_json.make_module('e', 'module', []), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set(), False, only_a, visit) expected_visited = ['d', 'b', 'a', 'e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_json_module_skips_filegroup_with_src_same_as_name(self): graph = [ soong_module_json.make_module( 'a', 'filegroup', [ soong_module_json.make_dep('b'), ], json_props=[ soong_module_json.make_property( name='Srcs', values=['other_file'], ), ], ), soong_module_json.make_module( 'b', 'filegroup', json_props=[ soong_module_json.make_property( name='Srcs', values=['b'], ), ], ), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set(), False, only_a, visit) expected_visited = ['a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_json_module_graph_post_order_include_created_by(self): graph = [ soong_module_json.make_module('a', 'module', [ soong_module_json.make_dep('b'), soong_module_json.make_dep('c'), ]), soong_module_json.make_module('b', 'module', created_by='d'), soong_module_json.make_module('c', 'module', [ soong_module_json.make_dep('e'), ]), soong_module_json.make_module('d', 'module', []), soong_module_json.make_module('e', 'module', []), ] def only_a(json): return json['Name'] == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module['Name']) dependency_analysis.visit_json_module_graph_post_order( graph, set(), False, only_a, visit) expected_visited = ['d', 'b', 'e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_queryview_xml_module_graph_post_order_visits_all(self): graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), queryview_xml.make_module( '//pkg:b', 'b', 'module', dep_names=['//pkg:d']), queryview_xml.make_module( '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), queryview_xml.make_module('//pkg:d', 'd', 'module'), queryview_xml.make_module('//pkg:e', 'e', 'module'), ]) def only_a(module): return module.name == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module.name) dependency_analysis.visit_queryview_xml_module_graph_post_order( graph, set(), only_a, visit) expected_visited = ['d', 'b', 'e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_queryview_xml_module_graph_post_order_skips_ignore_by_name( self): graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), queryview_xml.make_module( '//pkg:b', 'b', 'module', dep_names=['//pkg:d']), queryview_xml.make_module( '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), queryview_xml.make_module('//pkg:d', 'd', 'module'), queryview_xml.make_module('//pkg:e', 'e', 'module'), ]) def only_a(module): return module.name == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module.name) dependency_analysis.visit_queryview_xml_module_graph_post_order( graph, set('b'), only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_queryview_xml_module_graph_post_order_skips_default(self): graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), queryview_xml.make_module( '//pkg:b', 'b', 'module_defaults', dep_names=['//pkg:d']), queryview_xml.make_module( '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), queryview_xml.make_module('//pkg:d', 'd', 'module'), queryview_xml.make_module('//pkg:e', 'e', 'module'), ]) def only_a(module): return module.name == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module.name) dependency_analysis.visit_queryview_xml_module_graph_post_order( graph, set(), only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_queryview_xml_module_graph_post_order_skips_cc_prebuilt(self): graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), queryview_xml.make_module( '//pkg:b', 'b', 'cc_prebuilt_library', dep_names=['//pkg:d']), queryview_xml.make_module( '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), queryview_xml.make_module('//pkg:d', 'd', 'module'), queryview_xml.make_module('//pkg:e', 'e', 'module'), ]) def only_a(module): return module.name == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module.name) dependency_analysis.visit_queryview_xml_module_graph_post_order( graph, set(), only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_queryview_xml_module_graph_post_order_skips_filegroup_duplicate_name( self): graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), queryview_xml.make_module( '//pkg:b', 'b', 'filegroup', dep_names=['//pkg:d'], srcs=['b']), queryview_xml.make_module( '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), queryview_xml.make_module('//pkg:d', 'd', 'module'), queryview_xml.make_module('//pkg:e', 'e', 'module'), ]) def only_a(module): return module.name == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module.name) dependency_analysis.visit_queryview_xml_module_graph_post_order( graph, set(), only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_queryview_xml_module_graph_post_order_skips_windows(self): graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'module', dep_names=['//pkg:b', '//pkg:c']), queryview_xml.make_module( '//pkg:b', 'b', 'module', dep_names=['//pkg:d'], variant='windows-x86'), queryview_xml.make_module( '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), queryview_xml.make_module('//pkg:d', 'd', 'module'), queryview_xml.make_module('//pkg:e', 'e', 'module'), ]) def only_a(module): return module.name == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module.name) dependency_analysis.visit_queryview_xml_module_graph_post_order( graph, set(), only_a, visit) expected_visited = ['e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_queryview_xml_module_graph_post_order_self_dep_no_infinite_loop( self): graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'module', dep_names=['//pkg:b--variant1', '//pkg:c']), queryview_xml.make_module( '//pkg:b--variant1', 'b', 'module', variant='variant1', dep_names=['//pkg:b--variant2']), queryview_xml.make_module( '//pkg:b--variant2', 'b', 'module', variant='variant2', dep_names=['//pkg:d']), queryview_xml.make_module( '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), queryview_xml.make_module('//pkg:d', 'd', 'module'), queryview_xml.make_module('//pkg:e', 'e', 'module'), ]) def only_a(module): return module.name == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module.name) dependency_analysis.visit_queryview_xml_module_graph_post_order( graph, set(), only_a, visit) expected_visited = ['d', 'b', 'b', 'e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) def test_visit_queryview_xml_module_graph_post_order_skips_prebuilt_with_same_name( self): graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'module', dep_names=['//other_pkg:prebuilt_a', '//pkg:b', '//pkg:c']), queryview_xml.make_module('//other_pkg:prebuilt_a', 'prebuilt_a', 'prebuilt_module'), queryview_xml.make_module( '//pkg:b', 'b', 'module', dep_names=['//pkg:d']), queryview_xml.make_module( '//pkg:c', 'c', 'module', dep_names=['//pkg:e']), queryview_xml.make_module('//pkg:d', 'd', 'module'), queryview_xml.make_module('//pkg:e', 'e', 'module'), ]) def only_a(module): return module.name == 'a' visited_modules = [] def visit(module, _): visited_modules.append(module.name) dependency_analysis.visit_queryview_xml_module_graph_post_order( graph, set(), only_a, visit) expected_visited = ['d', 'b', 'e', 'c', 'a'] self.assertListEqual(visited_modules, expected_visited) if __name__ == '__main__': unittest.main()