• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright 2018, 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"""Unittests for module_info_utils."""
18
19import copy
20import logging
21import os.path
22import unittest
23from unittest import mock
24
25from aidegen import aidegen_main
26from aidegen import unittest_constants
27from aidegen.lib import common_util
28from aidegen.lib import errors
29from aidegen.lib import module_info_util
30from aidegen.lib import project_config
31
32from atest import atest_utils
33
34_TEST_CLASS_DICT = {'class': ['JAVA_LIBRARIES']}
35_TEST_SRCS_BAR_DICT = {'srcs': ['Bar']}
36_TEST_SRCS_BAZ_DICT = {'srcs': ['Baz']}
37_TEST_DEP_FOO_DIST = {'dependencies': ['Foo']}
38_TEST_DEP_SRC_DICT = {'dependencies': ['Foo'], 'srcs': ['Bar']}
39_TEST_DEP_SRC_MORE_DICT = {'dependencies': ['Foo'], 'srcs': ['Baz', 'Bar']}
40_TEST_MODULE_A_DICT = {
41    'module_a': {
42        'class': ['JAVA_LIBRARIES'],
43        'path': ['path_a'],
44        'installed': ['out/path_a/a.jar'],
45        'dependencies': ['Foo'],
46        'srcs': ['Bar'],
47        'compatibility_suites': ['null-suite'],
48        'module_name': ['ltp_fstat03_64']
49    }
50}
51_TEST_MODULE_A_DICT_HAS_NONEED_ITEMS = {
52    'module_a': {
53        'class': ['JAVA_LIBRARIES'],
54        'path': ['path_a'],
55        'installed': ['out/path_a/a.jar'],
56        'dependencies': ['Foo'],
57        'srcs': ['Bar'],
58        'compatibility_suites': ['null-suite'],
59        'module_name': ['ltp_fstat03_64']
60    }
61}
62_TEST_MODULE_A_JOIN_PATH_DICT = {
63    'module_a': {
64        'class': ['JAVA_LIBRARIES'],
65        'path': ['path_a'],
66        'installed': ['out/path_a/a.jar'],
67        'dependencies': ['Foo'],
68        'srcs': ['path_a/Bar']
69    }
70}
71
72
73# pylint: disable=invalid-name
74# pylint: disable=protected-access
75class AidegenModuleInfoUtilUnittests(unittest.TestCase):
76    """Unit tests for module_info_utils.py"""
77
78    @mock.patch.object(os.path, 'getmtime')
79    @mock.patch.object(logging, 'info')
80    @mock.patch.object(os.path, 'isfile')
81    @mock.patch.object(module_info_util, '_get_generated_json_files')
82    def test_of_build_bp_info_reuse_jsons(self, mock_json, mock_isfile,
83                                          mock_log, mock_time):
84        """Test of _build_bp_info to well reuse existing files."""
85        gen_files = ['file1', 'file_a', 'file_b']
86        mock_json.return_value = gen_files
87        # Test of the well reuse existing files.
88        mock_isfile.side_effect = (True, True, True)
89        mod_info = mock.MagicMock()
90        module_info_util._build_bp_info(mod_info, skip_build=True)
91        self.assertTrue(mock_json.called)
92        self.assertTrue(mock_log.called)
93        self.assertFalse(mock_time.called)
94
95    # pylint: disable=too-many-arguments
96    @mock.patch.object(module_info_util, '_generate_rust_project_link')
97    @mock.patch.object(module_info_util, '_show_build_failed_message')
98    @mock.patch.object(module_info_util, '_show_files_reuse_message')
99    @mock.patch.object(atest_utils, 'build')
100    @mock.patch.object(os.path, 'getmtime')
101    @mock.patch.object(logging, 'warning')
102    @mock.patch.object(os.path, 'isfile')
103    @mock.patch.object(module_info_util, '_get_generated_json_files')
104    def test_of_build_bp_info_rebuild_jsons(self, mock_json, mock_isfile,
105                                            mock_log, mock_time, mock_build,
106                                            mock_reuse, mock_fail,
107                                            mock_gen_rust):
108        """Test of _build_bp_info on rebuilding jsons."""
109        gen_files = ['file2', 'file_a', 'file_b']
110        mock_json.return_value = gen_files
111        mod_info = mock.MagicMock()
112        # Test of the existing files can't reuse.
113        mock_json.return_value = gen_files
114        mock_isfile.side_effect = (True, False, True)
115        mock_time.side_effect = (None, None, None)
116        mock_build.side_effect = (True, True)
117        module_info_util._build_bp_info(mod_info, skip_build=True)
118        self.assertTrue(mock_json.called)
119        self.assertTrue(mock_log.called)
120        self.assertTrue(mock_gen_rust.called)
121
122        # Test of the well rebuild case.
123        action_pass = '\nGenerate blueprint json successfully.'
124        self.assertTrue(mock_build.called)
125        self.assertTrue(mock_log.called_with(action_pass))
126        self.assertFalse(mock_reuse.called)
127        self.assertFalse(mock_fail.called)
128
129    @mock.patch.object(module_info_util, '_generate_rust_project_link')
130    @mock.patch.object(module_info_util, '_show_build_failed_message')
131    @mock.patch.object(module_info_util, '_show_files_reuse_message')
132    @mock.patch.object(module_info_util, '_is_new_json_file_generated')
133    @mock.patch.object(atest_utils, 'build')
134    @mock.patch.object(os.path, 'getmtime')
135    @mock.patch.object(logging, 'warning')
136    @mock.patch.object(os.path, 'isfile')
137    @mock.patch.object(module_info_util, '_get_generated_json_files')
138    def test_of_build_bp_info_show_build_fail(self, mock_json, mock_isfile,
139                                              mock_log, mock_time, mock_build,
140                                              mock_judge, mock_reuse,
141                                              mock_fail, mock_gen_rust):
142        """Test of _build_bp_info to show build failed message."""
143        gen_files = ['file3', 'file_a', 'file_b']
144        mock_json.return_value = gen_files
145        mod_info = mock.MagicMock()
146        # Test rebuild failed case - show build fail message.
147        mock_json.return_value = gen_files
148        test_prj = 'main'
149        mock_isfile.side_effect = (True, False, True)
150        mock_time.side_effect = (None, None, None)
151        mock_build.side_effect = (True, False)
152        mock_judge.side_effect = [True, False, False]
153        module_info_util._build_bp_info(mod_info, main_project=test_prj,
154                                        skip_build=False)
155        self.assertTrue(mock_json.called)
156        self.assertTrue(mock_log.called)
157        self.assertTrue(mock_build.called)
158        self.assertTrue(mock_gen_rust.called)
159        self.assertFalse(mock_reuse.called)
160        self.assertFalse(mock_fail.called)
161
162    @mock.patch.object(module_info_util, '_generate_rust_project_link')
163    @mock.patch.object(module_info_util, '_show_build_failed_message')
164    @mock.patch.object(module_info_util, '_show_files_reuse_message')
165    @mock.patch.object(module_info_util, '_is_new_json_file_generated')
166    @mock.patch.object(atest_utils, 'build')
167    @mock.patch.object(os.path, 'getmtime')
168    @mock.patch.object(logging, 'warning')
169    @mock.patch.object(os.path, 'isfile')
170    @mock.patch.object(module_info_util, '_get_generated_json_files')
171    def test_of_build_bp_info_rebuild_and_reuse(self, mock_json, mock_isfile,
172                                                mock_log, mock_time, mock_build,
173                                                mock_judge, mock_reuse,
174                                                mock_fail, mock_gen_rust):
175        """Test of _build_bp_info to reuse existing jsons."""
176        gen_files = ['file4', 'file_a', 'file_b']
177        mock_json.return_value = gen_files
178        mod_info = mock.MagicMock()
179        mock_json.return_value = gen_files
180        test_prj = 'main'
181        # Test rebuild failed case - show reuse message.
182        mock_isfile.side_effect = (True, True, True)
183        mock_time.side_effect = (None, None, None)
184        mock_build.side_effect = (True, False)
185        mock_judge.side_effect = [True, False, True]
186        module_info_util._build_bp_info(
187            mod_info, main_project=test_prj, skip_build=False)
188        self.assertTrue(mock_log.called)
189        self.assertTrue(mock_gen_rust.called)
190        self.assertFalse(mock_reuse.called)
191        self.assertFalse(mock_fail.called)
192
193    @mock.patch.object(module_info_util, '_generate_rust_project_link')
194    @mock.patch.object(module_info_util, '_show_build_failed_message')
195    @mock.patch.object(module_info_util, '_show_files_reuse_message')
196    @mock.patch.object(module_info_util, '_is_new_json_file_generated')
197    @mock.patch.object(atest_utils, 'build')
198    @mock.patch.object(os.path, 'getmtime')
199    @mock.patch.object(logging, 'warning')
200    @mock.patch.object(os.path, 'isfile')
201    @mock.patch.object(module_info_util, '_get_generated_json_files')
202    def test_of_build_bp_info_reuse_pass(self, mock_json, mock_isfile, mock_log,
203                                         mock_time, mock_build, mock_judge,
204                                         mock_reuse, mock_fail, mock_gen_rust):
205        """Test of _build_bp_info reuse pass."""
206        gen_files = ['file5', 'file_a', 'file_b']
207        mock_json.return_value = gen_files
208        test_prj = 'main'
209        mod_info = mock.MagicMock()
210        # Test rebuild failed case - show nothing.
211        mock_isfile.side_effect = (False, True, True)
212        mock_time.side_effect = (None, None, None)
213        mock_build.side_effect = (True, False)
214        mock_judge.side_effect = [True, True, True]
215        module_info_util._build_bp_info(mod_info, main_project=test_prj,
216                                        skip_build=False)
217        self.assertTrue(mock_log.called)
218        self.assertTrue(mock_gen_rust.called)
219        self.assertFalse(mock_reuse.called)
220        self.assertFalse(mock_fail.called)
221
222    # pylint: enable=too-many-arguments
223    def test_merge_module_keys_with_empty_dict(self):
224        """Test _merge_module_keys with an empty dictionary."""
225        test_b_dict = {}
226        test_m_dict = copy.deepcopy(_TEST_DEP_SRC_DICT)
227        module_info_util._merge_module_keys(test_m_dict, test_b_dict)
228        self.assertEqual(_TEST_DEP_SRC_DICT, test_m_dict)
229
230    def test_merge_module_keys_with_key_not_in_original_dict(self):
231        """Test _merge_module_keys with the key does not exist in the dictionary
232        to be merged into.
233        """
234        test_b_dict = _TEST_SRCS_BAR_DICT
235        test_m_dict = copy.deepcopy(_TEST_DEP_FOO_DIST)
236        module_info_util._merge_module_keys(test_m_dict, test_b_dict)
237        self.assertEqual(_TEST_DEP_SRC_DICT, test_m_dict)
238
239    def test_merge_module_keys_with_key_in_original_dict(self):
240        """Test _merge_module_keys with the key exists in the dictionary
241        to be merged into.
242        """
243        test_b_dict = _TEST_SRCS_BAZ_DICT
244        test_m_dict = copy.deepcopy(_TEST_DEP_SRC_DICT)
245        module_info_util._merge_module_keys(test_m_dict, test_b_dict)
246        self.assertEqual(
247            set(_TEST_DEP_SRC_MORE_DICT['srcs']), set(test_m_dict['srcs']))
248        self.assertEqual(
249            set(_TEST_DEP_SRC_MORE_DICT['dependencies']),
250            set(test_m_dict['dependencies']))
251
252    def test_merge_module_keys_with_duplicated_item_dict(self):
253        """Test _merge_module_keys with the key exists in the dictionary
254        to be merged into.
255        """
256        test_b_dict = _TEST_CLASS_DICT
257        test_m_dict = copy.deepcopy(_TEST_CLASS_DICT)
258        module_info_util._merge_module_keys(test_m_dict, test_b_dict)
259        self.assertEqual(_TEST_CLASS_DICT, test_m_dict)
260
261    def test_copy_needed_items_from_empty_dict(self):
262        """Test _copy_needed_items_from an empty dictionary."""
263        test_mk_dict = {}
264        want_dict = {}
265        self.assertEqual(want_dict,
266                         module_info_util._copy_needed_items_from(test_mk_dict))
267
268    def test_copy_needed_items_from_all_needed_items_dict(self):
269        """Test _copy_needed_items_from a dictionary with all needed items."""
270        self.assertEqual(
271            _TEST_MODULE_A_DICT,
272            module_info_util._copy_needed_items_from(_TEST_MODULE_A_DICT))
273
274    def test_copy_needed_items_from_some_needed_items_dict(self):
275        """Test _copy_needed_items_from a dictionary with some needed items."""
276        self.assertEqual(
277            _TEST_MODULE_A_DICT,
278            module_info_util._copy_needed_items_from(
279                _TEST_MODULE_A_DICT_HAS_NONEED_ITEMS))
280
281    @mock.patch.object(os.path, 'getmtime')
282    @mock.patch.object(atest_utils, 'build')
283    @mock.patch('os.path.isfile')
284    def test_build_bp_info_normal(self, mock_isfile, mock_build, mock_time):
285        """Test _build_target with verbose true and false."""
286        amodule_info = mock.MagicMock()
287        skip = True
288        mock_isfile.return_value = True
289        mock_build.return_value = True
290        module_info_util._build_bp_info(amodule_info, unittest_constants.
291                                        TEST_MODULE, False, skip)
292        self.assertFalse(mock_build.called)
293        skip = False
294        mock_time.return_value = float()
295        module_info_util._build_bp_info(amodule_info, unittest_constants.
296                                        TEST_MODULE, False, skip)
297        self.assertTrue(mock_time.called)
298        self.assertEqual(mock_build.call_count, 1)
299
300    @mock.patch('os.path.getmtime')
301    @mock.patch('os.path.isfile')
302    def test_is_new_json_file_generated(self, mock_isfile, mock_getmtime):
303        """Test _is_new_json_file_generated with different situations."""
304        jfile = 'path/test.json'
305        mock_isfile.return_value = False
306        self.assertFalse(
307            module_info_util._is_new_json_file_generated(jfile, None))
308        mock_isfile.return_value = True
309        self.assertTrue(
310            module_info_util._is_new_json_file_generated(jfile, None))
311        original_file_mtime = 1000
312        mock_getmtime.return_value = original_file_mtime
313        self.assertFalse(
314            module_info_util._is_new_json_file_generated(
315                jfile, original_file_mtime))
316        mock_getmtime.return_value = 1001
317        self.assertTrue(
318            module_info_util._is_new_json_file_generated(
319                jfile, original_file_mtime))
320
321    @mock.patch('builtins.input')
322    @mock.patch('glob.glob')
323    def test_build_failed_handle(self, mock_glob, mock_input):
324        """Test _build_failed_handle with different situations."""
325        mock_glob.return_value = ['project/file.iml']
326        mock_input.return_value = 'N'
327        with self.assertRaises(SystemExit) as cm:
328            module_info_util._build_failed_handle(
329                unittest_constants.TEST_MODULE)
330        self.assertEqual(cm.exception.code, 1)
331        mock_glob.return_value = []
332        with self.assertRaises(errors.BuildFailureError):
333            module_info_util._build_failed_handle(
334                unittest_constants.TEST_MODULE)
335
336    @mock.patch.object(project_config.ProjectConfig, 'get_instance')
337    @mock.patch.object(module_info_util, '_merge_dict')
338    @mock.patch.object(common_util, 'get_json_dict')
339    @mock.patch.object(module_info_util, '_build_bp_info')
340    def test_generate_merged_module_info(
341            self, mock_build, mock_get_soong, mock_merge_dict, mock_get_inst):
342        """Test generate_merged_module_info function."""
343        config = mock.MagicMock()
344        config.atest_module_info = mock.MagicMock()
345        main_project = 'tradefed'
346        args = aidegen_main._parse_args([main_project, '-n', '-v'])
347        config.targets = args.targets
348        config.verbose = args.verbose
349        config.is_skip_build = args.skip_build
350        module_info_util.generate_merged_module_info()
351        self.assertTrue(mock_get_inst.called)
352        self.assertTrue(mock_build.called)
353        self.assertTrue(mock_get_soong.called)
354        self.assertTrue(mock_merge_dict.called)
355
356    @mock.patch.object(common_util, 'get_blueprint_json_files_relative_dict')
357    def test_get_generated_json_files(self, mock_get_bp_dict):
358        """Test _get_generated_json_files function with conditions."""
359        a_env = 'GEN_A'
360        b_env = 'GEN_B'
361        a_file_path = 'a/b/path/to/a_file'
362        b_file_path = 'a/b/path/to/b_file'
363        file_paths = [a_file_path, b_file_path]
364        env_on = {a_env: 'true', b_env: 'true'}
365        mock_get_bp_dict.return_value = {a_env: a_file_path, b_env: b_file_path}
366        result_paths = file_paths
367        self.assertEqual(
368            result_paths, module_info_util._get_generated_json_files(env_on))
369        result_paths = []
370        env_on = {a_env: 'false', b_env: 'false'}
371        self.assertEqual(
372            result_paths, module_info_util._get_generated_json_files(env_on))
373        c_env = 'GEN_C'
374        d_env = 'GEN_D'
375        c_file_path = 'a/b/path/to/d_file'
376        d_file_path = 'a/b/path/to/d_file'
377        env_on = {a_env: 'true', b_env: 'true'}
378        mock_get_bp_dict.return_value = {c_env: c_file_path, d_env: d_file_path}
379        result_paths = []
380        self.assertEqual(
381            result_paths, module_info_util._get_generated_json_files(env_on))
382
383    @mock.patch.object(common_util, 'get_related_paths')
384    @mock.patch.object(module_info_util, '_build_failed_handle')
385    def test_show_build_failed_message(
386            self, mock_handle, mock_relpath):
387        """Test _show_build_failed_message with different conditions."""
388        main_project = ''
389        mock_relpath.return_value = 'c/d', 'a/b/c/d'
390        module_info_util._show_build_failed_message({}, main_project)
391        self.assertFalse(mock_handle.called)
392        main_project = 'tradefed'
393        module_info_util._show_build_failed_message({}, main_project)
394        self.assertTrue(mock_handle.called)
395
396    # pylint: disable=too-many-arguments
397    @mock.patch.object(module_info_util, '_show_build_failed_message')
398    @mock.patch.object(module_info_util, '_show_files_reuse_message')
399    @mock.patch.object(logging, 'warning')
400    @mock.patch.object(module_info_util, '_is_new_json_file_generated')
401    @mock.patch.object(atest_utils, 'build')
402    @mock.patch.object(os.path, 'getmtime')
403    @mock.patch.object(logging, 'info')
404    @mock.patch.object(os.path, 'isfile')
405    @mock.patch.object(module_info_util, '_get_generated_json_files')
406    def test_build_bp_info_skip(self, mock_gen_jsons, mock_isfile,
407                                mock_log_info, mock_get_mtimes, mock_build,
408                                mock_news, mock_warn, mock_show_reuse,
409                                mock_build_fail):
410        """Test _build_bp_info function with skip build."""
411        mock_gen_jsons.return_value = [
412            'a/b/out/soong/module_bp_java_deps.json',
413            'a/b/out/soong/module_bp_cc_deps.json'
414        ]
415        mock_isfile.return_value = True
416        module_info_util._build_bp_info(
417            module_info=mock.Mock(), skip_build=True)
418        self.assertTrue(mock_log_info.called)
419        self.assertFalse(mock_get_mtimes.called)
420        self.assertFalse(mock_build.called)
421        self.assertFalse(mock_news.called)
422        self.assertFalse(mock_warn.called)
423        self.assertFalse(mock_show_reuse.called)
424        self.assertFalse(mock_build_fail.called)
425
426    @mock.patch.object(module_info_util, '_show_build_failed_message')
427    @mock.patch.object(module_info_util, '_show_files_reuse_message')
428    @mock.patch.object(logging, 'warning')
429    @mock.patch.object(module_info_util, '_is_new_json_file_generated')
430    @mock.patch.object(atest_utils, 'build')
431    @mock.patch.object(os.path, 'getmtime')
432    @mock.patch.object(logging, 'info')
433    @mock.patch.object(os.path, 'isfile')
434    @mock.patch.object(module_info_util, '_get_generated_json_files')
435    def test_build_bp_info_no_skip(self, mock_gen_jsons, mock_isfile,
436                                   mock_log_info, mock_get_mtimes, mock_build,
437                                   mock_news, mock_warn, mock_show_reuse,
438                                   mock_build_fail):
439        """Test _build_bp_info function without skip build."""
440        mock_gen_jsons.return_value = [
441            'a/b/out/soong/module_bp_java_deps.json',
442            'a/b/out/soong/module_bp_cc_deps.json'
443        ]
444        mock_isfile.return_value = True
445        mock_build.return_value = True
446        module_info_util._build_bp_info(
447            module_info=mock.Mock(), skip_build=False)
448        self.assertTrue(mock_log_info.called)
449        self.assertTrue(mock_get_mtimes.called)
450        self.assertTrue(mock_build.called)
451        self.assertFalse(mock_news.called)
452        self.assertTrue(mock_warn.called)
453        self.assertFalse(mock_show_reuse.called)
454        self.assertFalse(mock_build_fail.called)
455
456    @mock.patch.object(module_info_util, '_show_build_failed_message')
457    @mock.patch.object(module_info_util, '_show_files_reuse_message')
458    @mock.patch.object(logging, 'warning')
459    @mock.patch.object(module_info_util, '_is_new_json_file_generated')
460    @mock.patch.object(atest_utils, 'build')
461    @mock.patch.object(os.path, 'getmtime')
462    @mock.patch.object(logging, 'info')
463    @mock.patch.object(os.path, 'isfile')
464    @mock.patch.object(module_info_util, '_get_generated_json_files')
465    def test_build_bp_info_failed(self, mock_gen_jsons, mock_isfile,
466                                  mock_log_info, mock_get_mtimes, mock_build,
467                                  mock_news, mock_warn, mock_show_reuse,
468                                  mock_build_fail):
469        """Test _build_bp_info function with build failed."""
470        mock_gen_jsons.return_value = [
471            'a/b/out/soong/module_bp_java_deps.json',
472            'a/b/out/soong/module_bp_cc_deps.json'
473        ]
474        mock_isfile.return_value = True
475        mock_build.return_value = False
476        mock_news.return_value = False
477        module_info_util._build_bp_info(
478            module_info=mock.Mock(), skip_build=False)
479        self.assertFalse(mock_log_info.called)
480        self.assertTrue(mock_get_mtimes.called)
481        self.assertTrue(mock_build.called)
482        self.assertTrue(mock_news.called)
483        self.assertTrue(mock_warn.called)
484        self.assertTrue(mock_show_reuse.called)
485        self.assertFalse(mock_build_fail.called)
486
487    @mock.patch.object(module_info_util, '_show_build_failed_message')
488    @mock.patch.object(module_info_util, '_show_files_reuse_message')
489    @mock.patch.object(logging, 'warning')
490    @mock.patch.object(module_info_util, '_is_new_json_file_generated')
491    @mock.patch.object(atest_utils, 'build')
492    @mock.patch.object(os.path, 'getmtime')
493    @mock.patch.object(logging, 'info')
494    @mock.patch.object(os.path, 'isfile')
495    @mock.patch.object(module_info_util, '_get_generated_json_files')
496    def test_build_bp_info_failed_not_exist(
497            self, mock_gen_jsons, mock_isfile, mock_log_info,
498            mock_get_mtimes, mock_build, mock_news, mock_warn, mock_show_reuse,
499            mock_build_fail):
500        """Test _build_bp_info function with build failed files not exist."""
501        mock_gen_jsons.return_value = [
502            'a/b/out/soong/module_bp_java_deps.json',
503            'a/b/out/soong/module_bp_cc_deps.json'
504        ]
505        mock_isfile.return_value = False
506        mock_build.return_value = False
507        mock_news.return_value = False
508        module_info_util._build_bp_info(
509            module_info=mock.Mock(), skip_build=False)
510        self.assertFalse(mock_log_info.called)
511        self.assertFalse(mock_get_mtimes.called)
512        self.assertTrue(mock_build.called)
513        self.assertTrue(mock_news.called)
514        self.assertTrue(mock_warn.called)
515        self.assertFalse(mock_show_reuse.called)
516        self.assertTrue(mock_build_fail.called)
517
518    @mock.patch.object(module_info_util, '_show_build_failed_message')
519    @mock.patch.object(module_info_util, '_show_files_reuse_message')
520    @mock.patch.object(logging, 'warning')
521    @mock.patch.object(module_info_util, '_is_new_json_file_generated')
522    @mock.patch.object(atest_utils, 'build')
523    @mock.patch.object(os.path, 'getmtime')
524    @mock.patch.object(logging, 'info')
525    @mock.patch.object(os.path, 'isfile')
526    @mock.patch.object(module_info_util, '_get_generated_json_files')
527    def test_build_bp_info_failed_files_exist(
528            self, mock_gen_jsons, mock_isfile, mock_log_info,
529            mock_get_mtimes, mock_build, mock_news, mock_warn, mock_show_reuse,
530            mock_build_fail):
531        """Test _build_bp_info function with build failed files not exist."""
532        mock_gen_jsons.return_value = [
533            'a/b/out/soong/module_bp_java_deps.json',
534            'a/b/out/soong/module_bp_cc_deps.json'
535        ]
536        mock_isfile.return_value = False
537        mock_build.return_value = False
538        mock_news.return_value = True
539        module_info_util._build_bp_info(
540            module_info=mock.Mock(), skip_build=False)
541        self.assertFalse(mock_log_info.called)
542        self.assertFalse(mock_get_mtimes.called)
543        self.assertTrue(mock_build.called)
544        self.assertTrue(mock_news.called)
545        self.assertTrue(mock_warn.called)
546        self.assertFalse(mock_show_reuse.called)
547        self.assertFalse(mock_build_fail.called)
548
549    @mock.patch('builtins.print')
550    @mock.patch('os.symlink')
551    @mock.patch('os.remove')
552    @mock.patch('os.path.islink')
553    @mock.patch('os.path.isfile')
554    def test_generate_rust_project_link(self, mock_isfile, mock_islink,
555                                        mock_remove, mock_symlink, mock_print):
556        """Test _generate_rust_project_link function."""
557        mock_isfile.return_value = True
558        mock_islink.return_value = False
559        module_info_util._generate_rust_project_link()
560        self.assertFalse(mock_print.called)
561        self.assertFalse(mock_remove.called)
562        self.assertTrue(mock_symlink.called)
563
564        mock_symlink.mock_reset()
565        mock_remove.mock_reset()
566        mock_print.mock_reset()
567        mock_islink.return_value = True
568        module_info_util._generate_rust_project_link()
569        self.assertTrue(mock_remove.called)
570        self.assertFalse(mock_print.called)
571        self.assertTrue(mock_symlink.called)
572
573        mock_symlink.mock_reset()
574        mock_remove.mock_reset()
575        mock_print.mock_reset()
576        mock_isfile.return_value = False
577        module_info_util._generate_rust_project_link()
578        self.assertTrue(mock_print.called)
579
580        mock_symlink.mock_reset()
581        mock_remove.mock_reset()
582        mock_print.mock_reset()
583        mock_islink.return_value = True
584        module_info_util._generate_rust_project_link()
585        self.assertTrue(mock_print.called)
586
587
588if __name__ == '__main__':
589    unittest.main()
590