• 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."""
18
19# pylint: disable=invalid-name
20# pylint: disable=line-too-long
21# pylint: disable=missing-function-docstring
22# pylint: disable=too-many-lines
23
24import os
25import shutil
26import tempfile
27import unittest
28
29from pathlib import Path
30from unittest import mock
31
32# pylint: disable=import-error
33from pyfakefs import fake_filesystem_unittest
34
35from atest import constants
36from atest import module_info
37from atest import unittest_utils
38from atest import unittest_constants as uc
39
40JSON_FILE_PATH = os.path.join(uc.TEST_DATA_DIR, uc.JSON_FILE)
41CC_DEP_PATH = os.path.join(uc.TEST_DATA_DIR, uc.CC_DEP_FILE)
42JAVA_DEP_PATH = os.path.join(uc.TEST_DATA_DIR, uc.JAVA_DEP_FILE)
43EXPECTED_MOD_TARGET = 'tradefed'
44EXPECTED_MOD_TARGET_PATH = ['tf/core']
45UNEXPECTED_MOD_TARGET = 'this_should_not_be_in_module-info.json'
46MOD_NO_PATH = 'module-no-path'
47PATH_TO_MULT_MODULES = 'shared/path/to/be/used'
48MULT_MOODULES_WITH_SHARED_PATH = ['module2', 'module1']
49PATH_TO_MULT_MODULES_WITH_MULTI_ARCH = 'shared/path/to/be/used2'
50TESTABLE_MODULES_WITH_SHARED_PATH = ['multiarch1', 'multiarch2', 'multiarch3', 'multiarch3_32']
51
52ROBO_MOD_PATH = ['/shared/robo/path']
53ROBO_MODULE = 'FooTests'
54ASSOCIATED_ROBO_MODULE = 'RunFooTests'
55ROBO_MODULE_INFO = {
56    constants.MODULE_NAME: ROBO_MODULE,
57    constants.MODULE_PATH: ROBO_MOD_PATH,
58    constants.MODULE_CLASS: [constants.MODULE_CLASS_JAVA_LIBRARIES]}
59ASSOCIATED_ROBO_MODULE_INFO = {
60    constants.MODULE_NAME: ASSOCIATED_ROBO_MODULE,
61    constants.MODULE_PATH: ROBO_MOD_PATH,
62    constants.MODULE_CLASS: [constants.MODULE_CLASS_ROBOLECTRIC]}
63MOD_PATH_INFO_DICT = {ROBO_MOD_PATH[0]: [ASSOCIATED_ROBO_MODULE_INFO, ROBO_MODULE_INFO]}
64MOD_NAME_INFO_DICT = {
65    ASSOCIATED_ROBO_MODULE: ASSOCIATED_ROBO_MODULE_INFO,
66    ROBO_MODULE: ROBO_MODULE_INFO}
67MOD_NAME1 = 'mod1'
68MOD_NAME2 = 'mod2'
69MOD_NAME3 = 'mod3'
70MOD_NAME4 = 'mod4'
71MOD_INFO_DICT = {}
72MODULE_INFO = {constants.MODULE_NAME: 'random_name',
73               constants.MODULE_PATH: 'a/b/c/path',
74               constants.MODULE_CLASS: ['random_class']}
75NAME_TO_MODULE_INFO = {'random_name' : MODULE_INFO}
76# Mocking path allows str only, use os.path instead of Path.
77with tempfile.TemporaryDirectory() as temp_dir:
78    BUILD_TOP_DIR = temp_dir
79SOONG_OUT_DIR = os.path.join(BUILD_TOP_DIR, 'out/soong')
80PRODUCT_OUT_DIR = os.path.join(BUILD_TOP_DIR, 'out/target/product/vsoc_x86_64')
81HOST_OUT_DIR = os.path.join(BUILD_TOP_DIR, 'out/host/linux-x86')
82
83# TODO: (b/263199608) Suppress too-many-public-methods after refactoring.
84#pylint: disable=protected-access, too-many-public-methods
85class ModuleInfoUnittests(unittest.TestCase):
86    """Unit tests for module_info.py"""
87
88    def setUp(self) -> None:
89        for path in [BUILD_TOP_DIR, PRODUCT_OUT_DIR, SOONG_OUT_DIR, HOST_OUT_DIR]:
90            if not Path(path).is_dir():
91                Path(path).mkdir(parents=True)
92        shutil.copy2(JSON_FILE_PATH, PRODUCT_OUT_DIR)
93        self.json_file_path = Path(PRODUCT_OUT_DIR).joinpath(uc.JSON_FILE)
94        shutil.copy2(CC_DEP_PATH, SOONG_OUT_DIR)
95        self.cc_dep_path = Path(SOONG_OUT_DIR).joinpath(uc.CC_DEP_FILE)
96        shutil.copy2(JAVA_DEP_PATH, SOONG_OUT_DIR)
97        self.java_dep_path = Path(SOONG_OUT_DIR).joinpath(uc.JAVA_DEP_FILE)
98        self.merged_dep_path = Path(PRODUCT_OUT_DIR).joinpath(uc.MERGED_DEP_FILE)
99
100    def tearDown(self) -> None:
101        if self.merged_dep_path.is_file():
102            os.remove(self.merged_dep_path)
103
104    # TODO: (b/264015241) Stop mocking build variables.
105    # TODO: (b/263199608) Re-write the test after refactoring module-info.py
106    @mock.patch.object(module_info.ModuleInfo, 'need_update_merged_file')
107    @mock.patch('json.load', return_value={})
108    @mock.patch('builtins.open', new_callable=mock.mock_open)
109    @mock.patch('os.path.isfile', return_value=True)
110    def test_load_mode_info_file_out_dir_handling(self, _isfile, _open, _json,
111        _merge):
112        """Test _load_module_info_file out dir handling."""
113        _merge.return_value = False
114        # Test out default out dir is used.
115        build_top = '/path/to/top'
116        default_out_dir = os.path.join(build_top, 'out/dir/here')
117        os_environ_mock = {'ANDROID_PRODUCT_OUT': default_out_dir,
118                           constants.ANDROID_BUILD_TOP: build_top}
119        default_out_dir_mod_targ = 'out/dir/here/module-info.json'
120        # Make sure module_info_target is what we think it is.
121        with mock.patch.dict('os.environ', os_environ_mock, clear=True):
122            mod_info = module_info.ModuleInfo(index_dir=HOST_OUT_DIR)
123            self.assertEqual(default_out_dir_mod_targ,
124                             mod_info.module_info_target)
125
126        # Test out custom out dir is used (OUT_DIR=dir2).
127        custom_out_dir = os.path.join(build_top, 'out2/dir/here')
128        os_environ_mock = {'ANDROID_PRODUCT_OUT': custom_out_dir,
129                           constants.ANDROID_BUILD_TOP: build_top}
130        custom_out_dir_mod_targ = 'out2/dir/here/module-info.json'
131        # Make sure module_info_target is what we think it is.
132        with mock.patch.dict('os.environ', os_environ_mock, clear=True):
133            mod_info = module_info.ModuleInfo(index_dir=HOST_OUT_DIR)
134            self.assertEqual(custom_out_dir_mod_targ,
135                             mod_info.module_info_target)
136
137        # Test out custom abs out dir is used (OUT_DIR=/tmp/out/dir2).
138        abs_custom_out_dir = '/tmp/out/dir'
139        os_environ_mock = {'ANDROID_PRODUCT_OUT': abs_custom_out_dir,
140                           constants.ANDROID_BUILD_TOP: build_top}
141        custom_abs_out_dir_mod_targ = '/tmp/out/dir/module-info.json'
142        # Make sure module_info_target is what we think it is.
143        with mock.patch.dict('os.environ', os_environ_mock, clear=True):
144            mod_info = module_info.ModuleInfo(index_dir=HOST_OUT_DIR)
145            self.assertEqual(custom_abs_out_dir_mod_targ,
146                             mod_info.module_info_target)
147
148    @mock.patch.object(module_info.ModuleInfo, '_load_module_info_file')
149    def test_get_path_to_module_info(self, mock_load_module):
150        """Test that we correctly create the path to module info dict."""
151        mod_one = 'mod1'
152        mod_two = 'mod2'
153        mod_path_one = '/path/to/mod1'
154        mod_path_two = '/path/to/mod2'
155        mod_info_dict = {mod_one: {constants.MODULE_PATH: [mod_path_one],
156                                   constants.MODULE_NAME: mod_one},
157                         mod_two: {constants.MODULE_PATH: [mod_path_two],
158                                   constants.MODULE_NAME: mod_two}}
159        mock_load_module.return_value = ('mod_target', mod_info_dict)
160        path_to_mod_info = {mod_path_one: [{constants.MODULE_NAME: mod_one,
161                                            constants.MODULE_PATH: [mod_path_one]}],
162                            mod_path_two: [{constants.MODULE_NAME: mod_two,
163                                            constants.MODULE_PATH: [mod_path_two]}]}
164        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH,
165                                          index_dir=HOST_OUT_DIR)
166        self.assertDictEqual(path_to_mod_info,
167                             mod_info._get_path_to_module_info(mod_info_dict))
168
169    def test_is_module(self):
170        """Test that we get the module when it's properly loaded."""
171        # Load up the test json file and check that module is in it
172        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
173        self.assertTrue(mod_info.is_module(EXPECTED_MOD_TARGET))
174        self.assertFalse(mod_info.is_module(UNEXPECTED_MOD_TARGET))
175
176    def test_get_path(self):
177        """Test that we get the module path when it's properly loaded."""
178        # Load up the test json file and check that module is in it
179        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
180        self.assertEqual(mod_info.get_paths(EXPECTED_MOD_TARGET),
181                         EXPECTED_MOD_TARGET_PATH)
182        self.assertEqual(mod_info.get_paths(MOD_NO_PATH), [])
183
184    def test_get_module_names(self):
185        """test that we get the module name properly."""
186        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
187        self.assertEqual(mod_info.get_module_names(EXPECTED_MOD_TARGET_PATH[0]),
188                         [EXPECTED_MOD_TARGET])
189        unittest_utils.assert_strict_equal(
190            self, mod_info.get_module_names(PATH_TO_MULT_MODULES),
191            MULT_MOODULES_WITH_SHARED_PATH)
192
193    def test_path_to_mod_info(self):
194        """test that we get the module name properly."""
195        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
196        module_list = []
197        for path_to_mod_info in mod_info.path_to_module_info[PATH_TO_MULT_MODULES_WITH_MULTI_ARCH]:
198            module_list.append(path_to_mod_info.get(constants.MODULE_NAME))
199        module_list.sort()
200        TESTABLE_MODULES_WITH_SHARED_PATH.sort()
201        self.assertEqual(module_list, TESTABLE_MODULES_WITH_SHARED_PATH)
202
203    def test_is_suite_in_compatibility_suites(self):
204        """Test is_suite_in_compatibility_suites."""
205        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
206        info = {'compatibility_suites': []}
207        self.assertFalse(mod_info.is_suite_in_compatibility_suites("cts", info))
208        info2 = {'compatibility_suites': ["cts"]}
209        self.assertTrue(mod_info.is_suite_in_compatibility_suites("cts", info2))
210        self.assertFalse(mod_info.is_suite_in_compatibility_suites("vts10", info2))
211        info3 = {'compatibility_suites': ["cts", "vts10"]}
212        self.assertTrue(mod_info.is_suite_in_compatibility_suites("cts", info3))
213        self.assertTrue(mod_info.is_suite_in_compatibility_suites("vts10", info3))
214        self.assertFalse(mod_info.is_suite_in_compatibility_suites("ats", info3))
215
216    # TODO: (b/264015241) Stop mocking build variables.
217    # TODO: (b/263199608) Re-write the test after refactoring module-info.py
218    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:'/',
219                                    constants.ANDROID_PRODUCT_OUT:PRODUCT_OUT_DIR,
220                                    constants.ANDROID_HOST_OUT:HOST_OUT_DIR})
221    @mock.patch.object(module_info.ModuleInfo, 'is_testable_module')
222    @mock.patch.object(module_info.ModuleInfo, 'is_suite_in_compatibility_suites')
223    def test_get_testable_modules(self, mock_is_suite_exist, mock_is_testable):
224        """Test get_testable_modules."""
225        # 1. No modules.idx yet, will run _get_testable_modules()
226        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH)
227        self.assertEqual(len(mod_info.get_testable_modules()), 29)
228
229        # 2. read modules.idx.
230        expected_modules = {'dep_test_module', 'MainModule2', 'test_dep_level_1_1'}
231        self.assertTrue(expected_modules.issubset(mod_info.get_testable_modules()))
232
233        # 3. search modules by giving a suite name, run _get_testable_modules()
234        mod_info.name_to_module_info = NAME_TO_MODULE_INFO
235        mock_is_testable.return_value = True
236        mock_is_suite_exist.return_value = True
237        self.assertEqual(1, len(mod_info.get_testable_modules('test_suite')))
238        mock_is_suite_exist.return_value = False
239        self.assertEqual(0, len(mod_info.get_testable_modules('test_suite')))
240        self.assertEqual(1, len(mod_info.get_testable_modules()))
241
242    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:'/',
243                                    constants.ANDROID_PRODUCT_OUT:PRODUCT_OUT_DIR})
244    @mock.patch.object(module_info.ModuleInfo, 'get_robolectric_type')
245    def test_is_robolectric_test(self, mock_type):
246        """Test is_robolectric_test."""
247        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
248        mock_type.return_value = constants.ROBOTYPE_MODERN
249        self.assertTrue(mod_info.is_robolectric_test(ROBO_MODULE))
250        mock_type.return_value = constants.ROBOTYPE_LEGACY
251        self.assertTrue(mod_info.is_robolectric_test(ROBO_MODULE))
252        mock_type.return_value = 0
253        self.assertFalse(mod_info.is_robolectric_test(ROBO_MODULE))
254
255    @mock.patch.object(module_info.ModuleInfo, 'is_module')
256    def test_is_auto_gen_test_config(self, mock_is_module):
257        """Test is_auto_gen_test_config correctly detects the module."""
258        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
259        mock_is_module.return_value = True
260        is_auto_test_config = {'auto_test_config': [True]}
261        is_not_auto_test_config = {'auto_test_config': [False]}
262        is_not_auto_test_config_again = {'auto_test_config': []}
263        MOD_INFO_DICT[MOD_NAME1] = is_auto_test_config
264        MOD_INFO_DICT[MOD_NAME2] = is_not_auto_test_config
265        MOD_INFO_DICT[MOD_NAME3] = is_not_auto_test_config_again
266        MOD_INFO_DICT[MOD_NAME4] = {}
267        mod_info.name_to_module_info = MOD_INFO_DICT
268        self.assertTrue(mod_info.is_auto_gen_test_config(MOD_NAME1))
269        self.assertFalse(mod_info.is_auto_gen_test_config(MOD_NAME2))
270        self.assertFalse(mod_info.is_auto_gen_test_config(MOD_NAME3))
271        self.assertFalse(mod_info.is_auto_gen_test_config(MOD_NAME4))
272
273    def test_merge_build_system_infos(self):
274        """Test _merge_build_system_infos."""
275        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
276        mod_info_1 = {constants.MODULE_NAME: 'module_1',
277                      constants.MODULE_DEPENDENCIES: []}
278        name_to_mod_info = {'module_1' : mod_info_1}
279        expect_deps = ['test_dep_level_1_1', 'test_dep_level_1_2']
280        name_to_mod_info = mod_info._merge_build_system_infos(
281            name_to_mod_info, java_bp_info_path=self.java_dep_path)
282        self.assertEqual(
283            name_to_mod_info['module_1'].get(constants.MODULE_DEPENDENCIES),
284            expect_deps)
285
286    def test_merge_build_system_infos_missing_keys(self):
287        """Test _merge_build_system_infos for keys missing from module-info.json."""
288        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
289        name_to_mod_info = mod_info._merge_build_system_infos(
290            {}, java_bp_info_path=self.java_dep_path)
291
292        expect_deps = ['test_dep_level_1_1']
293        self.assertEqual(
294            name_to_mod_info['not_in_module_info'].get(constants.MODULE_DEPENDENCIES),
295            expect_deps)
296
297    def test_merge_dependency_with_ori_dependency(self):
298        """Test _merge_dependency."""
299        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
300        mod_info_1 = {constants.MODULE_NAME: 'module_1',
301                      constants.MODULE_DEPENDENCIES: ['ori_dep_1']}
302        name_to_mod_info = {'module_1' : mod_info_1}
303        expect_deps = ['ori_dep_1', 'test_dep_level_1_1', 'test_dep_level_1_2']
304        name_to_mod_info = mod_info._merge_build_system_infos(
305            name_to_mod_info, java_bp_info_path=self.java_dep_path)
306        self.assertEqual(
307            name_to_mod_info['module_1'].get(constants.MODULE_DEPENDENCIES),
308            expect_deps)
309
310    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:uc.TEST_DATA_DIR,
311                                    constants.ANDROID_PRODUCT_OUT:PRODUCT_OUT_DIR})
312    def test_get_instrumentation_target_apps(self):
313        mod_info = module_info.ModuleInfo(
314            module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
315        artifacts = {
316            'AmSlam': {os.path.join(uc.TEST_DATA_DIR,
317                       "out/target/product/generic/data/app/AmSlam/AmSlam.apk")}
318        }
319        # 1. If Android.bp is available, use `manifest` to determine the actual
320        # manifest.
321        bp_context = """android_test    {
322            name: "AmSlamTests",
323            manifest: 'AndroidManifest.xml',
324            instrumentation_for: "AmSlam"
325        }"""
326        bp_file = os.path.join(uc.TEST_DATA_DIR, 'foo/bar/AmSlam/test/Android.bp')
327        with open(bp_file, 'w', encoding='utf-8') as cache:
328            cache.write(bp_context)
329        self.assertEqual(
330            mod_info.get_instrumentation_target_apps('AmSlamTests'), artifacts)
331        os.remove(bp_file)
332        # 2. If Android.bp is unavailable, search `AndroidManifest.xml`
333        # arbitrarily.
334        self.assertEqual(
335            mod_info.get_instrumentation_target_apps('AmSlamTests'), artifacts)
336
337    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:uc.TEST_DATA_DIR,
338                                    constants.ANDROID_PRODUCT_OUT:PRODUCT_OUT_DIR})
339    def test_get_target_module_by_pkg(self):
340        mod_info = module_info.ModuleInfo(
341            module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
342        self.assertEqual(
343            'AmSlam',
344            mod_info.get_target_module_by_pkg(
345                package='c0m.andr0id.settingS',
346                search_from=Path(uc.TEST_DATA_DIR).joinpath('foo/bar/AmSlam/test')))
347
348    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:uc.TEST_DATA_DIR,
349                                    constants.ANDROID_PRODUCT_OUT:PRODUCT_OUT_DIR})
350    def test_get_artifact_map(self):
351        mod_info = module_info.ModuleInfo(
352            module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
353        artifacts = {
354            'AmSlam': {os.path.join(uc.TEST_DATA_DIR,
355                       'out/target/product/generic/data/app/AmSlam/AmSlam.apk')}
356        }
357        self.assertEqual(mod_info.get_artifact_map('AmSlam'), artifacts)
358
359    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:uc.TEST_DATA_DIR,
360                                    constants.ANDROID_PRODUCT_OUT:PRODUCT_OUT_DIR})
361    def test_get_filepath_from_module(self):
362        """Test for get_filepath_from_module."""
363        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
364
365        expected_filepath = Path(uc.TEST_DATA_DIR).joinpath(
366            'foo/bar/AmSlam', 'AndroidManifest.xml')
367        self.assertEqual(
368            mod_info.get_filepath_from_module('AmSlam', 'AndroidManifest.xml'),
369            expected_filepath)
370
371        expected_filepath = Path(uc.TEST_DATA_DIR).joinpath(
372            'foo/bar/AmSlam/test', 'AndroidManifest.xml')
373        self.assertEqual(
374            mod_info.get_filepath_from_module('AmSlamTests', 'AndroidManifest.xml'),
375            expected_filepath)
376
377    def test_get_module_dependency(self):
378        """Test get_module_dependency."""
379        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
380        expect_deps = {'test_dep_level_1_1', 'module_1', 'test_dep_level_1_2',
381                       'test_dep_level_2_2', 'test_dep_level_2_1', 'module_2'}
382        mod_info._merge_build_system_infos(mod_info.name_to_module_info,
383                                   java_bp_info_path=self.java_dep_path)
384        self.assertEqual(
385            mod_info.get_module_dependency('dep_test_module'),
386            expect_deps)
387
388    def test_get_module_dependency_w_loop(self):
389        """Test get_module_dependency with problem dep file."""
390        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
391        # Java dependency file with a endless loop define.
392        java_dep_file = os.path.join(uc.TEST_DATA_DIR,
393                                     'module_bp_java_loop_deps.json')
394        expect_deps = {'test_dep_level_1_1', 'module_1', 'test_dep_level_1_2',
395                       'test_dep_level_2_2', 'test_dep_level_2_1', 'module_2'}
396        mod_info._merge_build_system_infos(mod_info.name_to_module_info,
397                                   java_bp_info_path=java_dep_file)
398        self.assertEqual(
399            mod_info.get_module_dependency('dep_test_module'),
400            expect_deps)
401
402    def test_get_install_module_dependency(self):
403        """Test get_install_module_dependency."""
404        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
405        expect_deps = {'module_1', 'test_dep_level_2_1'}
406        mod_info._merge_build_system_infos(mod_info.name_to_module_info,
407                                           java_bp_info_path=self.java_dep_path)
408        self.assertEqual(
409            mod_info.get_install_module_dependency('dep_test_module'),
410            expect_deps)
411
412    def test_cc_merge_build_system_infos(self):
413        """Test _merge_build_system_infos for cc."""
414        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
415        mod_info_1 = {constants.MODULE_NAME: 'module_cc_1',
416                      constants.MODULE_DEPENDENCIES: []}
417        name_to_mod_info = {'module_cc_1' : mod_info_1}
418        expect_deps = ['test_cc_dep_level_1_1', 'test_cc_dep_level_1_2']
419        name_to_mod_info = mod_info._merge_build_system_infos(
420            name_to_mod_info, cc_bp_info_path=self.cc_dep_path)
421        self.assertEqual(
422            name_to_mod_info['module_cc_1'].get(constants.MODULE_DEPENDENCIES),
423            expect_deps)
424
425    def test_is_unit_test(self):
426        """Test is_unit_test."""
427        module_name = 'myModule'
428        maininfo_with_unittest = {constants.MODULE_NAME: module_name,
429                                  constants.MODULE_IS_UNIT_TEST: 'true'}
430        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH,
431                                          index_dir=HOST_OUT_DIR)
432        self.assertTrue(mod_info.is_unit_test(maininfo_with_unittest))
433
434    def test_is_host_unit_test(self):
435        """Test is_host_unit_test."""
436        module_name = 'myModule'
437        maininfo_with_host_unittest = {
438            constants.MODULE_NAME: module_name,
439            constants.MODULE_IS_UNIT_TEST: 'true',
440            'compatibility_suites': ['host-unit-tests'],
441            constants.MODULE_INSTALLED: uc.DEFAULT_INSTALL_PATH,
442            'auto_test_config': ['true']
443        }
444
445        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH,
446                                          index_dir=HOST_OUT_DIR)
447
448        self.assertTrue(mod_info.is_host_unit_test(maininfo_with_host_unittest))
449
450    def test_is_device_driven_test(self):
451        module_name = 'myModule'
452        maininfo_with_device_driven_test = {
453            constants.MODULE_NAME: module_name,
454            constants.MODULE_TEST_CONFIG:[os.path.join(
455                     uc.TEST_CONFIG_DATA_DIR, "a.xml.data")],
456            constants.MODULE_INSTALLED: uc.DEFAULT_INSTALL_PATH,
457            'supported_variants': ['DEVICE']
458        }
459        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
460
461        self.assertTrue(mod_info.is_device_driven_test(maininfo_with_device_driven_test))
462
463    def test_not_device_driven_test_when_suite_is_robolectric_test(self):
464        module_name = 'myModule'
465        maininfo_with_device_driven_test = {
466            constants.MODULE_NAME: module_name,
467            constants.MODULE_TEST_CONFIG:[os.path.join(
468                     uc.TEST_CONFIG_DATA_DIR, "a.xml.data")],
469            constants.MODULE_INSTALLED: uc.DEFAULT_INSTALL_PATH,
470            'supported_variants': ['DEVICE'],
471            'compatibility_suites': ['robolectric-tests'],
472        }
473        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
474
475        self.assertFalse(mod_info.is_device_driven_test(maininfo_with_device_driven_test))
476
477    def test_is_host_driven_test(self):
478        """Test is_host_driven_test."""
479        test_name = 'myModule'
480        expected_host_driven_info  = {
481            constants.MODULE_NAME: test_name,
482            constants.MODULE_TEST_CONFIG:[os.path.join(
483                uc.TEST_CONFIG_DATA_DIR, "a.xml.data")],
484            constants.MODULE_INSTALLED: uc.DEFAULT_INSTALL_PATH,
485            'supported_variants': ['HOST']
486        }
487        mod_info = create_module_info([
488            module(
489                name=test_name,
490                test_config=[os.path.join(uc.TEST_CONFIG_DATA_DIR,
491                             "a.xml.data")],
492                installed=uc.DEFAULT_INSTALL_PATH,
493                supported_variants=['HOST']
494            )
495        ])
496
497        return_value = mod_info.is_host_driven_test(expected_host_driven_info)
498
499        self.assertTrue(return_value)
500
501    # TODO: (b/264015241) Stop mocking build variables.
502    # TODO: (b/263199608) Re-write the test after refactoring module-info.py
503    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:os.path.dirname(__file__),
504                                    constants.ANDROID_PRODUCT_OUT:PRODUCT_OUT_DIR})
505    def test_has_mainline_modules(self):
506        """Test has_mainline_modules."""
507        name1 = 'MainModule1'
508        mainline_module1 = ['foo2.apk', 'foo3.apk']
509        name2 = 'MainModule2'
510        mainline_module2 = ['foo1.apex']
511        name3 = 'MainModule3'
512
513        mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH, index_dir=HOST_OUT_DIR)
514        # found in 'test_mainlne_modules' attribute.
515        self.assertTrue(mod_info.has_mainline_modules(name1, mainline_module1))
516        # found in the value of 'mainline-param' in test_config.
517        self.assertTrue(mod_info.has_mainline_modules(name2, mainline_module2))
518        # cannot be found in both 'test_mainline_modules' and 'test_config'.
519        self.assertFalse(mod_info.has_mainline_modules(name3, mainline_module2))
520
521    # TODO: (b/264015241) Stop mocking build variables.
522    # TODO: (b/263199608) Re-write the test after refactoring module-info.py
523    @mock.patch.dict('os.environ',
524                     {constants.ANDROID_BUILD_TOP:os.path.dirname(__file__),
525                      constants.ANDROID_PRODUCT_OUT:PRODUCT_OUT_DIR})
526    def test_get_module_info_for_multi_lib_module(self):
527        my_module_name = 'MyMultiArchTestModule'
528        multi_arch_json = os.path.join(uc.TEST_DATA_DIR,
529                                       'multi_arch_module-info.json')
530        mod_info = module_info.ModuleInfo(module_file=multi_arch_json, index_dir=HOST_OUT_DIR)
531
532        self.assertIsNotNone(mod_info.get_module_info(my_module_name))
533
534    def test_get_modules_by_include_deps_w_testable_module_only_false(self):
535        module_1 = module(name='module_1',
536                          dependencies=['dep1', 'dep2'],
537                          )
538        module_2 = module(name='module_2',
539                          dependencies=['dep1', 'dep3']
540                          )
541        mod_info = create_module_info([module_1, module_2])
542
543        self.assertEqual({'module_1', 'module_2'},
544                         mod_info.get_modules_by_include_deps(
545                             {'dep1'}, testable_module_only=False))
546        self.assertEqual({'module_1'},
547                         mod_info.get_modules_by_include_deps(
548                             {'dep2'}, testable_module_only=False))
549        self.assertEqual({'module_2'},
550                         mod_info.get_modules_by_include_deps(
551                             {'dep3'}, testable_module_only=False))
552
553    @mock.patch.object(module_info.ModuleInfo, 'get_testable_modules')
554    def test_get_modules_by_include_deps_w_testable_module_only_true(
555            self, _testable_modules):
556        module_1 = module(name='module_1',
557                          dependencies=['dep1', 'dep2'],
558                          )
559        module_2 = module(name='module_2',
560                          dependencies=['dep1', 'dep3']
561                          )
562        mod_info = create_module_info([module_1, module_2])
563        _testable_modules.return_value = []
564
565        self.assertEqual(set(),
566                         mod_info.get_modules_by_include_deps(
567                             {'dep1'}, testable_module_only=True))
568
569    def test_get_modules_by_path_in_srcs_no_module_found(self):
570        module_1 = module(name='module_1',
571                          srcs=['path/src1', 'path/src2'],
572                          )
573        module_2 = module(name='module_2',
574                          srcs=['path/src2', 'path/src3']
575                          )
576        mod_info = create_module_info([module_1, module_2])
577
578        self.assertEqual(set(),
579                         mod_info.get_modules_by_path_in_srcs('path/src4'))
580
581    def test_get_modules_by_path_in_srcs_one_module_found(self):
582        module_1 = module(name='module_1',
583                          srcs=['path/src1', 'path/src2'],
584                          )
585        module_2 = module(name='module_2',
586                          srcs=['path/src2', 'path/src3']
587                          )
588        mod_info = create_module_info([module_1, module_2])
589
590        self.assertEqual({'module_1'},
591                         mod_info.get_modules_by_path_in_srcs('path/src1'))
592
593    def test_get_modules_by_path_in_srcs_multiple_module_found(self):
594        module_1 = module(name='module_1',
595                          srcs=['path/src1', 'path/src2'],
596                          )
597        module_2 = module(name='module_2',
598                          srcs=['path/src2', 'path/src3']
599                          )
600        mod_info = create_module_info([module_1, module_2])
601
602        self.assertEqual({'module_1', 'module_2'},
603                         mod_info.get_modules_by_path_in_srcs('path/src2'))
604
605    def test_contains_same_mainline_modules(self):
606        mainline_modules = {'A.apex', 'B.apk'}
607        self.assertTrue(module_info.contains_same_mainline_modules(
608            mainline_modules,
609            {'B.apk+A.apex'}))
610        self.assertFalse(module_info.contains_same_mainline_modules(
611            mainline_modules,
612            {'B.apk+C.apex'}))
613
614
615class ModuleInfoTestFixture(fake_filesystem_unittest.TestCase):
616    """Fixture for ModuleInfo tests."""
617
618    def setUp(self):
619        self.setUpPyfakefs()
620
621    # pylint: disable=protected-access
622    def create_empty_module_info(self):
623        fake_temp_file_name = next(tempfile._get_candidate_names())
624        self.fs.create_file(fake_temp_file_name, contents='{}')
625        return module_info.ModuleInfo(module_file=fake_temp_file_name)
626
627    def create_module_info(self, modules=None):
628        mod_info = self.create_empty_module_info()
629        modules = modules or []
630
631        for m in modules:
632            mod_info.name_to_module_info[m['module_name']] = m
633            for path in m['path']:
634                if path in mod_info.path_to_module_info:
635                    mod_info.path_to_module_info[path].append(m)
636                else:
637                    mod_info.path_to_module_info[path] = [m]
638
639        return mod_info
640
641
642class HasTestConfonfigTest(ModuleInfoTestFixture):
643    """Tests has_test_config in various conditions."""
644
645    def test_return_true_if_test_config_is_not_empty(self):
646        test_module_info = module(test_config=['config_file'])
647        mod_info = self.create_module_info()
648
649        return_value = mod_info.has_test_config(test_module_info)
650
651        self.assertTrue(return_value)
652
653    def test_return_true_if_auto_test_config_is_not_empty(self):
654        test_module_info = module(auto_test_config=['no_empty'])
655        mod_info = self.create_module_info()
656
657        return_value = mod_info.has_test_config(test_module_info)
658
659        self.assertTrue(return_value)
660
661    def test_return_false_if_auto_test_config_and_test_config_empty(self):
662        test_module_info = module(test_config=[],
663                                  auto_test_config=[])
664        mod_info = self.create_module_info()
665
666        return_value = mod_info.has_test_config(test_module_info)
667
668        self.assertFalse(return_value)
669
670
671class ModuleInfoCompatibilitySuiteTest(ModuleInfoTestFixture):
672    """Tests the compatibility suite in the module info."""
673
674    def test_return_true_if_suite_in_test(self):
675        test_module_info = module(compatibility_suites=['test_suite'])
676        mod_info = self.create_module_info()
677
678        return_value = mod_info.is_suite_in_compatibility_suites(
679            'test_suite', test_module_info)
680
681        self.assertTrue(return_value)
682
683    def test_return_false_if_suite_not_in_test(self):
684        test_module_info = module(compatibility_suites=['no_suite'])
685        mod_info = self.create_module_info()
686
687        return_value = mod_info.is_suite_in_compatibility_suites(
688            'test_suite', test_module_info)
689
690        self.assertFalse(return_value)
691
692    def test_return_false_when_mod_info_is_empty(self):
693        test_module_info = None
694        mod_info = self.create_module_info()
695
696        return_value = mod_info.is_suite_in_compatibility_suites(
697            'test_suite', test_module_info)
698
699        self.assertFalse(return_value)
700
701    def test_return_false_when_mod_info_is_not_a_dict(self):
702        test_module_info = ['no_a_dict']
703        mod_info = self.create_module_info()
704
705        return_value = mod_info.is_suite_in_compatibility_suites(
706            'test_suite', test_module_info)
707
708        self.assertFalse(return_value)
709
710
711class RobolectricTestNameTest(ModuleInfoTestFixture):
712    """Tests the Robolectric test name in the module info."""
713
714    def test_return_empty_for_a_modern_robolectric_test(self):
715        module_name = 'hello_world_test'
716        mod_info = self.create_module_info(modules=[
717            modern_robolectric_test_module(name=f'{module_name}'),
718        ])
719
720        return_module = mod_info.get_robolectric_test_name(module_name)
721
722        self.assertEqual('', return_module)
723
724    def test_return_related_robolectric_run_module_name(self):
725        module_name = 'hello_world_test'
726        run_module_name = f'Run{module_name}'
727        module_path = 'robolectric_path'
728        mod_info = self.create_module_info(modules=[
729            test_module(name=f'{module_name}',
730                        path=module_path),
731            robolectric_class_test_module(name=f'{run_module_name}',
732                                          path=module_path),
733        ])
734
735        return_module = mod_info.get_robolectric_test_name(module_name)
736
737        self.assertEqual(run_module_name, return_module)
738
739    def test_return_empty_when_no_related_robolectic_class_module(self):
740        module_name = 'hello_world_test'
741        run_module_name = f'Run{module_name}'
742        module_path = 'robolectric_path'
743        mod_info = self.create_module_info(modules=[
744            test_module(name=f'{module_name}',
745                        path=module_path),
746            test_module(name=f'{run_module_name}',
747                        path=module_path),
748        ])
749
750        return_module = mod_info.get_robolectric_test_name(module_name)
751
752        self.assertEqual('', return_module)
753
754    def test_return_empty_if_related_module_name_not_start_with_Run(self):
755        module_name = 'hello_world_test'
756        run_module_name = f'Not_Run{module_name}'
757        module_path = 'robolectric_path'
758        mod_info = self.create_module_info(modules=[
759            test_module(name=f'{module_name}',
760                        path=module_path),
761            robolectric_class_test_module(name=f'{run_module_name}',
762                                          path=module_path),
763        ])
764
765        return_module = mod_info.get_robolectric_test_name(module_name)
766
767        self.assertEqual('', return_module)
768
769    def test_return_itself_for_a_robolectric_class_test_module(self):
770        module_name = 'Run_hello_world_test'
771        mod_info = self.create_module_info(modules=[
772            robolectric_class_test_module(name=f'{module_name}'),
773        ])
774
775        return_module = mod_info.get_robolectric_test_name(module_name)
776
777        self.assertEqual(module_name, return_module)
778
779    def test_return_empty_if_robolectric_class_module_not_start_with_Run(self):
780        module_name = 'hello_world_test'
781        mod_info = self.create_module_info(modules=[
782            robolectric_class_test_module(name=f'{module_name}'),
783        ])
784
785        return_module = mod_info.get_robolectric_test_name(module_name)
786
787        self.assertEqual('', return_module)
788
789    def test_return_0_when_no_mod_info(self):
790        module_name = 'hello_world_test'
791        mod_info = self.create_module_info()
792
793        return_module = mod_info.get_robolectric_test_name(module_name)
794
795        self.assertEqual('', return_module)
796
797
798class RobolectricTestTypeTest(ModuleInfoTestFixture):
799    """Tests the Robolectric test type in the module info."""
800
801    def test_modern_robolectric_test_type(self):
802        module_name = 'hello_world_test'
803        mod_info = self.create_module_info(modules=[
804            modern_robolectric_test_module(name=f'{module_name}'),
805        ])
806
807        return_value = mod_info.get_robolectric_type(module_name)
808
809        self.assertEqual(return_value, constants.ROBOTYPE_MODERN)
810
811    def test_return_modern_if_compliant_with_modern_and_legacy(self):
812        module_name = 'hello_world_test'
813        module_path = 'robolectric_path'
814        run_module_name = f'Run{module_name}'
815        mod_info = self.create_module_info(modules=[
816            modern_robolectric_test_module(name=f'{module_name}',
817                        path=module_path),
818            robolectric_class_test_module(name=f'{run_module_name}',
819                                          path=module_path),
820        ])
821
822        return_value = mod_info.get_robolectric_type(module_name)
823
824        self.assertEqual(return_value, constants.ROBOTYPE_MODERN)
825
826    def test_not_modern_robolectric_test_if_suite_is_not_robolectric(self):
827        module_name = 'hello_world_test'
828        mod_info = self.create_module_info(modules=[
829            test_module(name=f'{module_name}',
830                        compatibility_suites='not_robolectric_tests'),
831        ])
832
833        return_value = mod_info.get_robolectric_type(module_name)
834
835        self.assertEqual(return_value, 0)
836
837    def test_legacy_robolectric_test_type(self):
838        module_name = 'hello_world_test'
839        run_module_name = f'Run{module_name}'
840        module_path = 'robolectric_path'
841        mod_info = self.create_module_info(modules=[
842            test_module(name=f'{module_name}',
843                        path=module_path),
844            robolectric_class_test_module(name=f'{run_module_name}',
845                                          path=module_path),
846        ])
847
848        return_value = mod_info.get_robolectric_type(module_name)
849
850        self.assertEqual(return_value, constants.ROBOTYPE_LEGACY)
851
852    def test_robolectric_class_test_module(self):
853        module_name = 'Run_hello_world_test'
854        mod_info = self.create_module_info(modules=[
855            robolectric_class_test_module(name=f'{module_name}'),
856        ])
857
858        return_value = mod_info.get_robolectric_type(module_name)
859
860        self.assertEqual(return_value, constants.ROBOTYPE_LEGACY)
861
862    def test_not_robolectric_test_if_module_name_not_start_with_Run(self):
863        module_name = 'hello_world_test'
864        mod_info = self.create_module_info(modules=[
865            robolectric_class_test_module(name=f'{module_name}'),
866        ])
867
868        return_value = mod_info.get_robolectric_type(module_name)
869
870        self.assertEqual(return_value, 0)
871
872    def test_return_0_when_no_related_robolectic_class_module(self):
873        module_name = 'hello_world_test'
874        run_module_name = f'Run{module_name}'
875        module_path = 'robolectric_path'
876        mod_info = self.create_module_info(modules=[
877            test_module(name=f'{module_name}',
878                        path=module_path),
879            test_module(name=f'{run_module_name}',
880                        path=module_path),
881        ])
882
883        return_value = mod_info.get_robolectric_type(module_name)
884
885        self.assertEqual(return_value, 0)
886
887    def test_return_0_when_no_related_module_name_start_with_Run(self):
888        module_name = 'hello_world_test'
889        run_module_name = f'Not_Run{module_name}'
890        module_path = 'robolectric_path'
891        mod_info = self.create_module_info(modules=[
892            test_module(name=f'{module_name}',
893                        path=module_path),
894            robolectric_class_test_module(name=f'{run_module_name}',
895                                          path=module_path),
896        ])
897
898        return_value = mod_info.get_robolectric_type(module_name)
899
900        self.assertEqual(return_value, 0)
901
902    def test_return_0_when_no_mod_info(self):
903        module_name = 'hello_world_test'
904        mod_info = self.create_module_info()
905
906        return_value = mod_info.get_robolectric_type(module_name)
907
908        self.assertEqual(return_value, 0)
909
910
911class IsLegacyRobolectricClassTest(ModuleInfoTestFixture):
912    """Tests is_legacy_robolectric_class in various conditions."""
913
914    def test_return_true_if_module_class_is_robolectric(self):
915        test_module_info = module(classes=[constants.MODULE_CLASS_ROBOLECTRIC])
916        mod_info = self.create_module_info()
917
918        return_value = mod_info.is_legacy_robolectric_class(test_module_info)
919
920        self.assertTrue(return_value)
921
922    def test_return_false_if_module_class_is_not_robolectric(self):
923        test_module_info = module(classes=['not_robolectric'])
924        mod_info = self.create_module_info()
925
926        return_value = mod_info.is_legacy_robolectric_class(test_module_info)
927
928        self.assertFalse(return_value)
929
930    def test_return_false_if_module_class_is_empty(self):
931        test_module_info = module(classes=[])
932        mod_info = self.create_module_info()
933
934        return_value = mod_info.is_legacy_robolectric_class(test_module_info)
935
936        self.assertFalse(return_value)
937
938
939class IsTestableModuleTest(ModuleInfoTestFixture):
940    """Tests is_testable_module in various conditions."""
941
942    def test_return_true_for_tradefed_testable_module(self):
943        info = test_module()
944        mod_info = self.create_module_info()
945
946        return_value = mod_info.is_testable_module(info)
947
948        self.assertTrue(return_value)
949
950    def test_return_true_for_modern_robolectric_test_module(self):
951        info = modern_robolectric_test_module()
952        mod_info = self.create_module_info()
953
954        return_value = mod_info.is_testable_module(info)
955
956        self.assertTrue(return_value)
957
958    def test_return_true_for_legacy_robolectric_test_module(self):
959        info = legacy_robolectric_test_module()
960        mod_info = self.create_module_info()
961
962        return_value = mod_info.is_testable_module(info)
963
964        self.assertTrue(return_value)
965
966    def test_return_false_for_non_tradefed_testable_module(self):
967        info = module(auto_test_config=[], test_config=[],
968                      installed=['installed_path'])
969        mod_info = self.create_module_info()
970
971        return_value = mod_info.is_testable_module(info)
972
973        self.assertFalse(return_value)
974
975    def test_return_false_for_no_installed_path_module(self):
976        info = module(auto_test_config=['true'], installed=[])
977        mod_info = self.create_module_info()
978
979        return_value = mod_info.is_testable_module(info)
980
981        self.assertFalse(return_value)
982
983    def test_return_false_if_module_info_is_empty(self):
984        info = {}
985        mod_info = self.create_module_info()
986
987        return_value = mod_info.is_testable_module(info)
988
989        self.assertFalse(return_value)
990
991
992@mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP: '/'})
993def create_empty_module_info():
994    with fake_filesystem_unittest.Patcher() as patcher:
995        # pylint: disable=protected-access
996        fake_temp_file_name = next(tempfile._get_candidate_names())
997        patcher.fs.create_file(fake_temp_file_name, contents='{}')
998        return module_info.ModuleInfo(module_file=fake_temp_file_name)
999
1000
1001def create_module_info(modules=None):
1002    mod_info = create_empty_module_info()
1003    modules = modules or []
1004
1005    for m in modules:
1006        mod_info.name_to_module_info[m['module_name']] = m
1007
1008    return mod_info
1009
1010
1011def test_module(**kwargs):
1012    kwargs.setdefault('name', 'hello_world_test')
1013    return test(module(**kwargs))
1014
1015
1016def modern_robolectric_test_module(**kwargs):
1017    kwargs.setdefault('name', 'hello_world_test')
1018    return test(robolectric_tests_suite(module(**kwargs)))
1019
1020
1021def legacy_robolectric_test_module(**kwargs):
1022    kwargs.setdefault('name', 'Run_hello_world_test')
1023    return test(robolectric_tests_suite(module(**kwargs)))
1024
1025
1026def robolectric_class_test_module(**kwargs):
1027    kwargs.setdefault('name', 'hello_world_test')
1028    return test(robolectric_class(module(**kwargs)))
1029
1030
1031# pylint: disable=too-many-arguments, too-many-locals
1032def module(
1033    name=None,
1034    path=None,
1035    installed=None,
1036    classes=None,
1037    auto_test_config=None,
1038    test_config=None,
1039    shared_libs=None,
1040    dependencies=None,
1041    runtime_dependencies=None,
1042    data=None,
1043    data_dependencies=None,
1044    compatibility_suites=None,
1045    host_dependencies=None,
1046    srcs=None,
1047    supported_variants=None
1048):
1049    name = name or 'libhello'
1050
1051    m = {}
1052
1053    m['module_name'] = name
1054    m['class'] = classes or ['ETC']
1055    m['path'] = [path or '']
1056    m['installed'] = installed or []
1057    m['is_unit_test'] = 'false'
1058    m['auto_test_config'] = auto_test_config or []
1059    m['test_config'] = test_config or []
1060    m['shared_libs'] = shared_libs or []
1061    m['runtime_dependencies'] = runtime_dependencies or []
1062    m['dependencies'] = dependencies or []
1063    m['data'] = data or []
1064    m['data_dependencies'] = data_dependencies or []
1065    m['compatibility_suites'] = compatibility_suites or []
1066    m['host_dependencies'] = host_dependencies or []
1067    m['srcs'] = srcs or []
1068    m['supported_variants'] = supported_variants or []
1069    return m
1070
1071
1072def test(info):
1073    info['auto_test_config'] = ['true']
1074    info['installed'] = ['installed_path']
1075    return info
1076
1077
1078def robolectric_class(info):
1079    info['class'] = ['ROBOLECTRIC']
1080    return info
1081
1082
1083def robolectric_tests_suite(info):
1084    info = test(info)
1085    info.setdefault('compatibility_suites', []).append('robolectric-tests')
1086    return info
1087
1088
1089if __name__ == '__main__':
1090    unittest.main()
1091