• 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 project_file_gen."""
18
19import logging
20import os
21import shutil
22import unittest
23from unittest import mock
24
25from aidegen import unittest_constants
26from aidegen.idea import xml_gen
27from aidegen.lib import common_util
28from aidegen.lib import config
29from aidegen.lib import project_config
30from aidegen.lib import project_file_gen
31from aidegen.lib import project_info
32from aidegen.project import project_splitter
33
34
35# pylint: disable=protected-access
36# pylint: disable-msg=too-many-arguments
37class AidegenProjectFileGenUnittest(unittest.TestCase):
38    """Unit tests for project_file_gen.py."""
39
40    maxDiff = None
41    _TEST_DATA_PATH = unittest_constants.TEST_DATA_PATH
42    _ANDROID_PROJECT_PATH = unittest_constants.ANDROID_PROJECT_PATH
43    _PROJECT_PATH = os.path.join(_TEST_DATA_PATH, 'project')
44    _ANDROID_FACET_SAMPLE = os.path.join(_TEST_DATA_PATH, 'android_facet.iml')
45    _PROJECT_FACET_SAMPLE = os.path.join(_TEST_DATA_PATH, 'project_facet.iml')
46    _MODULE_DEP_SAMPLE = os.path.join(_TEST_DATA_PATH, 'module_dependency.iml')
47    _IML_SAMPLE = os.path.join(_TEST_DATA_PATH, 'test.iml')
48    _DEPENDENCIES_IML_SAMPLE = os.path.join(_TEST_DATA_PATH, 'dependencies.iml')
49    _MODULE_XML_SAMPLE = os.path.join(_TEST_DATA_PATH, 'modules.xml')
50    _MAIN_MODULE_XML_SAMPLE = os.path.join(_TEST_DATA_PATH,
51                                           'modules_only_self_module.xml')
52    _ENABLE_DEBUGGER_MODULE_SAMPLE = os.path.join(
53        _TEST_DATA_PATH, 'modules_with_enable_debugger.xml')
54    _IML_PATH = os.path.join(_ANDROID_PROJECT_PATH, 'android_project.iml')
55    _DEPENDENCIES_IML_PATH = os.path.join(_ANDROID_PROJECT_PATH,
56                                          'dependencies.iml')
57    _IDEA_PATH = os.path.join(_ANDROID_PROJECT_PATH, '.idea')
58    _MODULE_PATH = os.path.join(_IDEA_PATH, 'modules.xml')
59    _SOURCE_SAMPLE = os.path.join(_TEST_DATA_PATH, 'source.iml')
60    _SRCJAR_SAMPLE = os.path.join(_TEST_DATA_PATH, 'srcjar.iml')
61    _AOSP_FOLDER = '/aosp'
62    _TEST_SOURCE_LIST = [
63        'a/b/c/d', 'a/b/c/d/e', 'a/b/c/d/e/f', 'a/b/c/d/f', 'e/f/a', 'e/f/b/c',
64        'e/f/g/h'
65    ]
66    _ANDROID_SOURCE_RELATIVE_PATH = 'test_data/project'
67    _SAMPLE_CONTENT_LIST = ['a/b/c/d', 'e/f']
68    _SAMPLE_TRIMMED_SOURCE_LIST = ['a/b/c/d', 'e/f/a', 'e/f/b/c', 'e/f/g/h']
69
70    def _init_project_config(self, args):
71        """Initialize project configurations."""
72        self.assertIsNotNone(args)
73        pconfig = project_config.ProjectConfig(args)
74        pconfig.init_environment()
75
76    @mock.patch.object(project_config, 'ProjectConfig')
77    @mock.patch.object(project_info, 'ProjectInfo')
78    def test_generate_modules_xml(self, mock_project, mock_config):
79        """Test _generate_modules_xml."""
80        mock_config.is_launch_ide = True
81        mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
82        pfile_gen = project_file_gen.ProjectFileGenerator(mock_project)
83        # Test for main project.
84        try:
85            pfile_gen._generate_modules_xml([])
86            project_file_gen.update_enable_debugger(self._ANDROID_PROJECT_PATH)
87            test_module = common_util.read_file_content(self._MODULE_PATH)
88        finally:
89            shutil.rmtree(self._IDEA_PATH)
90        sample_module = common_util.read_file_content(self._MODULE_XML_SAMPLE)
91        self.assertEqual(test_module, sample_module)
92
93        # Test for sub projects which only has self module.
94        try:
95            pfile_gen._generate_modules_xml()
96            project_file_gen.update_enable_debugger(self._ANDROID_PROJECT_PATH)
97            test_module = common_util.read_file_content(self._MODULE_PATH)
98        finally:
99            shutil.rmtree(self._IDEA_PATH)
100        sample_module = common_util.read_file_content(
101            self._MAIN_MODULE_XML_SAMPLE)
102        self.assertEqual(test_module, sample_module)
103
104    @mock.patch.object(project_file_gen, '_get_all_git_path')
105    @mock.patch.object(xml_gen, 'write_ignore_git_dirs_file')
106    @mock.patch.object(xml_gen, 'gen_vcs_xml')
107    @mock.patch.object(common_util, 'get_android_root_dir')
108    @mock.patch.object(common_util, 'find_git_root')
109    @mock.patch.object(project_info, 'ProjectInfo')
110    def test_merge_project_vcs_xmls(self, mock_project, mock_get_git_root,
111                                    mock_get_root, mock_write, mock_ignore_git,
112                                    mock_all_git_path):
113        """Test _merge_project_vcs_xmls."""
114        mock_get_root.return_value = '/a/b'
115        mock_project.project_absolute_path = '/a/b/c'
116        mock_project.project_relative_path = 'c'
117        mock_get_git_root.return_value = '/a/b/c'
118        project_file_gen._merge_project_vcs_xmls([mock_project])
119        self.assertTrue(mock_write.called_with('/a/b/c', '/a/b/c'))
120        mock_project.project_absolute_path = '/a/b'
121        mock_project.project_relative_path = None
122        mock_get_git_root.return_value = None
123        mock_all_git_path.return_value = ['/a', '/b']
124        project_file_gen._merge_project_vcs_xmls([mock_project])
125        self.assertTrue(mock_write.called_with('/a/b', [None]))
126        self.assertTrue(mock_ignore_git.called_with('/a/b', ['/a', '/b']))
127
128    @mock.patch.object(project_info, 'ProjectInfo')
129    def test_copy_project_files(self, mock_project):
130        """Test _copy_constant_project_files."""
131        mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
132        project_file_gen.ProjectFileGenerator(
133            mock_project)._copy_constant_project_files()
134        self.assertTrue(
135            os.path.isfile(
136                os.path.join(self._IDEA_PATH,
137                             project_file_gen._CODE_STYLE_FOLDER,
138                             'codeStyleConfig.xml')))
139
140        self.assertTrue(
141            os.path.isfile(
142                os.path.join(self._IDEA_PATH,
143                             project_file_gen._INSPECTION_FOLDER,
144                             'profiles_settings.xml')))
145
146        self.assertTrue(
147            os.path.isfile(
148                os.path.join(self._IDEA_PATH,
149                             project_file_gen._INSPECTION_FOLDER,
150                             'Aidegen_Inspections.xml')))
151
152        self.assertTrue(
153            os.path.isfile(
154                os.path.join(self._IDEA_PATH,
155                             project_file_gen._COPYRIGHT_FOLDER,
156                             'Apache_2.xml')))
157        self.assertTrue(
158            os.path.isfile(
159                os.path.join(self._IDEA_PATH,
160                             project_file_gen._COPYRIGHT_FOLDER,
161                             'profiles_settings.xml')))
162        shutil.rmtree(self._IDEA_PATH)
163
164    @mock.patch.object(logging, 'error')
165    @mock.patch.object(shutil, 'copy')
166    @mock.patch.object(os.path, 'exists')
167    def test_generate_git_ignore(self, mock_path_exist, mock_copy,
168                                 mock_loggin_error):
169        """Test _generate_git_ignore."""
170        mock_path_exist.return_value = True
171        project_file_gen._generate_git_ignore(
172            common_util.get_aidegen_root_dir())
173        self.assertFalse(mock_copy.called)
174
175        # Test for creating symlink exception.
176        mock_path_exist.return_value = False
177        mock_copy.side_effect = OSError()
178        project_file_gen._generate_git_ignore(
179            common_util.get_aidegen_root_dir())
180        self.assertTrue(mock_loggin_error.called)
181
182    def test_filter_out_source_paths(self):
183        """Test _filter_out_source_paths."""
184        test_set = {'a/a.java', 'b/b.java', 'c/c.java'}
185        module_relpath = {'a', 'c'}
186        expected_result = {'b/b.java'}
187        result_set = project_file_gen._filter_out_source_paths(test_set,
188                                                               module_relpath)
189        self.assertEqual(result_set, expected_result)
190
191    @mock.patch.object(project_config, 'ProjectConfig')
192    @mock.patch.object(project_info, 'ProjectInfo')
193    def test_update_enable_debugger(self, mock_project, mock_config):
194        """Test update_enable_debugger."""
195        mock_config.is_launch_ide = True
196        enable_debugger_iml = '/path/to/enable_debugger/enable_debugger.iml'
197        sample_module = common_util.read_file_content(
198            self._ENABLE_DEBUGGER_MODULE_SAMPLE)
199        mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
200        pfile_gen = project_file_gen.ProjectFileGenerator(mock_project)
201        try:
202            pfile_gen._generate_modules_xml([])
203            project_file_gen.update_enable_debugger(self._ANDROID_PROJECT_PATH,
204                                                    enable_debugger_iml)
205            test_module = common_util.read_file_content(self._MODULE_PATH)
206            self.assertEqual(test_module, sample_module)
207        finally:
208            shutil.rmtree(self._IDEA_PATH)
209
210    @mock.patch.object(common_util, 'find_git_root')
211    @mock.patch.object(project_file_gen.ProjectFileGenerator,
212                       '_generate_modules_xml')
213    @mock.patch.object(project_info, 'ProjectInfo')
214    def test_generate_intellij_project_file(self, mock_project,
215                                            mock_gen_xml, mock_get_git_path):
216        """Test generate_intellij_project_file."""
217        mock_project.project_absolute_path = self._ANDROID_PROJECT_PATH
218        mock_get_git_path.return_value = 'git/path'
219        project_gen = project_file_gen.ProjectFileGenerator(mock_project)
220        project_gen.project_info.is_main_project = False
221        project_gen.generate_intellij_project_file()
222        self.assertFalse(mock_gen_xml.called)
223        project_gen.project_info.is_main_project = True
224        project_gen.generate_intellij_project_file()
225        self.assertTrue(mock_gen_xml.called)
226
227    @mock.patch.object(os, 'walk')
228    def test_get_all_git_path(self, mock_os_walk):
229        """Test _get_all_git_path."""
230        # Test .git folder exists.
231        mock_os_walk.return_value = [('/root', ['.git', 'a'], None)]
232        test_result = list(project_file_gen._get_all_git_path('/root'))
233        expected_result = ['/root']
234        self.assertEqual(test_result, expected_result)
235
236        # Test .git folder does not exist.
237        mock_os_walk.return_value = [('/root', ['a'], None)]
238        test_result = list(project_file_gen._get_all_git_path('/root'))
239        expected_result = []
240        self.assertEqual(test_result, expected_result)
241
242    @mock.patch.object(common_util, 'file_generate')
243    @mock.patch.object(os.path, 'isfile')
244    def test_generate_test_mapping_schema(self, mock_is_file,
245                                          mock_file_generate):
246        """Test _generate_test_mapping_schema."""
247        mock_is_file.return_value = False
248        project_file_gen._generate_test_mapping_schema('')
249        self.assertFalse(mock_file_generate.called)
250        mock_is_file.return_value = True
251        project_file_gen._generate_test_mapping_schema('')
252        self.assertTrue(mock_file_generate.called)
253
254    @mock.patch.object(project_file_gen, 'update_enable_debugger')
255    @mock.patch.object(config.AidegenConfig, 'create_enable_debugger_module')
256    def test_gen_enable_debugger_module(self, mock_create_module,
257                                        mock_update_module):
258        """Test gen_enable_debugger_module."""
259        android_sdk_path = None
260        project_file_gen.gen_enable_debugger_module('a', android_sdk_path)
261        self.assertFalse(mock_create_module.called)
262        mock_create_module.return_value = False
263        project_file_gen.gen_enable_debugger_module('a', 'b')
264        self.assertFalse(mock_update_module.called)
265        mock_create_module.return_value = True
266        project_file_gen.gen_enable_debugger_module('a', 'b')
267        self.assertTrue(mock_update_module.called)
268
269    @mock.patch.object(project_config.ProjectConfig, 'get_instance')
270    @mock.patch.object(project_file_gen, '_merge_project_vcs_xmls')
271    @mock.patch.object(project_file_gen.ProjectFileGenerator,
272                       'generate_intellij_project_file')
273    @mock.patch.object(project_splitter.ProjectSplitter, 'gen_projects_iml')
274    @mock.patch.object(project_splitter.ProjectSplitter,
275                       'gen_framework_srcjars_iml')
276    @mock.patch.object(project_splitter.ProjectSplitter,
277                       'revise_source_folders')
278    @mock.patch.object(project_splitter.ProjectSplitter, 'get_dependencies')
279    @mock.patch.object(common_util, 'get_android_root_dir')
280    @mock.patch.object(project_info, 'ProjectInfo')
281    def test_generate_ide_project_files(self, mock_project, mock_get_root,
282                                        mock_get_dep, mock_revise_src,
283                                        mock_gen_framework_srcjars,
284                                        mock_gen_projects_iml, mock_gen_file,
285                                        mock_merge_vcs, mock_project_config):
286        """Test generate_ide_project_files."""
287        mock_get_root.return_value = '/aosp'
288        mock_project.project_absolute_path = '/aosp'
289        mock_project.project_relative_path = ''
290        project_cfg = mock.Mock()
291        mock_project_config.return_value = project_cfg
292        project_cfg.full_repo = True
293        gen_proj = project_file_gen.ProjectFileGenerator
294        gen_proj.generate_ide_project_files([mock_project])
295        self.assertTrue(mock_get_dep.called)
296        self.assertTrue(mock_revise_src.called)
297        self.assertTrue(mock_gen_framework_srcjars.called)
298        self.assertTrue(mock_gen_projects_iml.called)
299        self.assertTrue(mock_gen_file.called)
300        self.assertTrue(mock_merge_vcs.called)
301
302
303if __name__ == '__main__':
304    unittest.main()
305