• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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