#!/usr/bin/env python3 # # Copyright 2020 - The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Unittests for project_splitter.""" import os import shutil import tempfile import unittest from unittest import mock from aidegen import constant from aidegen import unittest_constants from aidegen.idea import iml from aidegen.lib import common_util from aidegen.lib import project_config from aidegen.lib import project_info from aidegen.project import project_splitter # pylint: disable=protected-access class ProjectSplitterUnittest(unittest.TestCase): """Unit tests for ProjectSplitter class.""" _TEST_DIR = None _TEST_PATH = unittest_constants.TEST_DATA_PATH _SAMPLE_EXCLUDE_FOLDERS = [ '\n ' % _TEST_PATH, '\n ' % _TEST_PATH, ] def setUp(self): """Prepare the testdata related data.""" projects = [] targets = ['a', 'b', 'c', 'framework'] ProjectSplitterUnittest._TEST_DIR = tempfile.mkdtemp() for i, target in enumerate(targets): with mock.patch.object(project_info, 'ProjectInfo') as proj_info: projects.append(proj_info(target, i == 0)) projects[0].project_relative_path = 'src1' projects[0].source_path = { 'source_folder_path': {'src1', 'src2', 'other1'}, 'test_folder_path': {'src1/tests'}, 'jar_path': {'jar1.jar'}, 'jar_module_path': {}, 'r_java_path': set(), 'srcjar_path': {'srcjar1.srcjar'} } projects[1].project_relative_path = 'src2' projects[1].source_path = { 'source_folder_path': {'src2', 'src2/src3', 'src2/lib', 'other2'}, 'test_folder_path': {'src2/tests'}, 'jar_path': set(), 'jar_module_path': {}, 'r_java_path': set(), 'srcjar_path': {'srcjar2.srcjar'} } projects[2].project_relative_path = 'src2/src3' projects[2].source_path = { 'source_folder_path': {'src2/src3', 'src2/lib'}, 'test_folder_path': {'src2/src3/tests'}, 'jar_path': {'jar3.jar'}, 'jar_module_path': {}, 'r_java_path': set(), 'srcjar_path': {'srcjar3.srcjar'} } projects[3].project_relative_path = 'frameworks/base' projects[3].source_path = { 'source_folder_path': set(), 'test_folder_path': set(), 'jar_path': set(), 'jar_module_path': {}, 'r_java_path': set(), 'srcjar_path': {'framework.srcjar', 'other.srcjar'} } with mock.patch.object(project_config.ProjectConfig, 'get_instance') as proj_cfg: config = mock.Mock() config.full_repo = False proj_cfg.return_value = config self.split_projs = project_splitter.ProjectSplitter(projects) def tearDown(self): """Clear the testdata related path.""" self.split_projs = None shutil.rmtree(ProjectSplitterUnittest._TEST_DIR) iml.IMLGenerator.USED_NAME_CACHE.clear() @mock.patch.object(common_util, 'get_android_root_dir') @mock.patch.object(project_config.ProjectConfig, 'get_instance') @mock.patch('builtins.any') def test_init(self, mock_any, mock_project, mock_root): """Test initialize the attributes.""" self.assertEqual(len(self.split_projs._projects), 4) mock_any.return_value = False mock_root.return_value = ProjectSplitterUnittest._TEST_DIR with mock.patch.object(project_info, 'ProjectInfo') as proj_info: config = mock.Mock() config.full_repo = False mock_project.return_value = config project = project_splitter.ProjectSplitter(proj_info(['a'], True)) self.assertFalse(project._framework_exist) config.full_repo = True project = project_splitter.ProjectSplitter(proj_info(['a'], True)) self.assertEqual(project._full_repo_iml, os.path.basename( ProjectSplitterUnittest._TEST_DIR)) @mock.patch.object(project_splitter.ProjectSplitter, '_remove_duplicate_sources') @mock.patch.object(project_splitter.ProjectSplitter, '_keep_local_sources') @mock.patch.object(project_splitter.ProjectSplitter, '_collect_all_srcs') def test_revise_source_folders(self, mock_copy_srcs, mock_keep_srcs, mock_remove_srcs): """Test revise_source_folders.""" self.split_projs.revise_source_folders() self.assertTrue(mock_copy_srcs.called) self.assertTrue(mock_keep_srcs.called) self.assertTrue(mock_remove_srcs.called) def test_collect_all_srcs(self): """Test _collect_all_srcs.""" self.split_projs._collect_all_srcs() sources = self.split_projs._all_srcs expected_srcs = {'src1', 'src2', 'src2/src3', 'src2/lib', 'other1', 'other2'} self.assertEqual(sources['source_folder_path'], expected_srcs) expected_tests = {'src1/tests', 'src2/tests', 'src2/src3/tests'} self.assertEqual(sources['test_folder_path'], expected_tests) def test_keep_local_sources(self): """Test _keep_local_sources.""" self.split_projs._collect_all_srcs() self.split_projs._keep_local_sources() srcs1 = self.split_projs._projects[0].source_path srcs2 = self.split_projs._projects[1].source_path srcs3 = self.split_projs._projects[2].source_path all_srcs = self.split_projs._all_srcs expected_srcs1 = {'src1'} expected_srcs2 = {'src2', 'src2/src3', 'src2/lib'} expected_srcs3 = {'src2/src3'} expected_all_srcs = {'other1', 'other2'} expected_all_tests = set() self.assertEqual(srcs1['source_folder_path'], expected_srcs1) self.assertEqual(srcs2['source_folder_path'], expected_srcs2) self.assertEqual(srcs3['source_folder_path'], expected_srcs3) self.assertEqual(all_srcs['source_folder_path'], expected_all_srcs) self.assertEqual(all_srcs['test_folder_path'], expected_all_tests) @mock.patch.object( project_splitter, '_remove_child_duplicate_sources_from_parent') def test_remove_duplicate_sources(self, mock_remove): """Test _remove_duplicate_sources.""" self.split_projs._collect_all_srcs() self.split_projs._keep_local_sources() mock_remove.return_value = set() self.split_projs._remove_duplicate_sources() srcs2 = self.split_projs._projects[1].source_path srcs3 = self.split_projs._projects[2].source_path expected_srcs2 = {'src2', 'src2/lib'} expected_srcs3 = {'src2/src3'} self.assertEqual(srcs2['source_folder_path'], expected_srcs2) self.assertEqual(srcs3['source_folder_path'], expected_srcs3) self.assertTrue(mock_remove.called) def test_get_dependencies(self): """Test get_dependencies.""" iml.IMLGenerator.USED_NAME_CACHE.clear() self.split_projs.get_dependencies() dep1 = ['framework_srcjars', 'base', 'src2', 'dependencies'] dep2 = ['framework_srcjars', 'base', 'dependencies'] dep3 = ['framework_srcjars', 'base', 'src2', 'dependencies'] self.assertEqual(self.split_projs._projects[0].dependencies, dep1) self.assertEqual(self.split_projs._projects[1].dependencies, dep2) self.assertEqual(self.split_projs._projects[2].dependencies, dep3) @mock.patch.object(iml.IMLGenerator, 'create') @mock.patch.object(project_splitter.ProjectSplitter, '_get_permission_defined_source_path') @mock.patch.object(project_splitter.ProjectSplitter, '_remove_permission_definition_srcjar_path') @mock.patch.object(common_util, 'get_android_root_dir') def test_gen_framework_srcjars_iml( self, mock_root, mock_remove, mock_get, mock_create_iml): """Test gen_framework_srcjars_iml.""" mock_root.return_value = self._TEST_DIR mock_get.return_value = 'aapt2/R' self.split_projs._projects[0].dep_modules = { 'framework-all': { 'module_name': 'framework-all', 'path': ['frameworks/base'], 'srcjars': ['framework.srcjar'], 'iml_name': 'framework_srcjars' } } self.split_projs._framework_exist = False self.split_projs.gen_framework_srcjars_iml() srcjar_dict = {constant.KEY_DEP_SRCS: True, constant.KEY_SRCJARS: True, constant.KEY_DEPENDENCIES: True} mock_create_iml.assert_called_with(srcjar_dict) expected_srcjars = [ 'other.srcjar', 'srcjar1.srcjar', 'srcjar2.srcjar', 'srcjar3.srcjar', ] expected_path = os.path.join(self._TEST_DIR, 'frameworks/base/framework_srcjars.iml') self.split_projs._framework_exist = True self.split_projs.revise_source_folders() mock_get.return_value = None iml_path = self.split_projs.gen_framework_srcjars_iml() srcjars = self.split_projs._all_srcs['srcjar_path'] self.assertEqual(sorted(list(srcjars)), expected_srcjars) self.assertEqual(iml_path, expected_path) self.assertTrue(mock_remove.called) srcjar_dict = {constant.KEY_SRCJARS: True, constant.KEY_DEPENDENCIES: True} mock_create_iml.assert_called_with(srcjar_dict) @mock.patch.object(project_splitter.ProjectSplitter, '_unzip_all_scrjars') @mock.patch.object(iml.IMLGenerator, 'create') @mock.patch.object(common_util, 'get_android_root_dir') def test_gen_dependencies_iml(self, mock_root, mock_create_iml, mock_unzip): """Test _gen_dependencies_iml.""" mock_root.return_value = self._TEST_DIR self.split_projs.revise_source_folders() self.split_projs._framework_exist = False self.split_projs._gen_dependencies_iml() self.assertTrue(mock_unzip.called) mock_unzip.mock_reset() self.split_projs._framework_exist = True self.split_projs._gen_dependencies_iml() self.assertTrue(mock_create_iml.called) self.assertTrue(mock_unzip.called) @mock.patch.object(project_splitter.ProjectSplitter, '_unzip_all_scrjars') @mock.patch.object(project_splitter, 'get_exclude_content') @mock.patch.object(project_config.ProjectConfig, 'get_instance') @mock.patch.object(iml.IMLGenerator, 'create') @mock.patch.object(common_util, 'get_android_root_dir') def test_gen_projects_iml(self, mock_root, mock_create_iml, mock_project, mock_get_excludes, mock_unzip): """Test gen_projects_iml.""" mock_root.return_value = self._TEST_DIR config = mock.Mock() mock_project.return_value = config config.exclude_paths = [] self.split_projs.revise_source_folders() self.split_projs.gen_projects_iml() self.assertTrue(mock_create_iml.called) self.assertTrue(mock_unzip.called) mock_unzip.mock_reset() self.assertFalse(mock_get_excludes.called) config.exclude_paths = ['a'] self.split_projs.gen_projects_iml() self.assertTrue(mock_get_excludes.called) self.assertTrue(mock_unzip.called) def test_get_exclude_content(self): """Test get_exclude_content.""" exclude_folders = project_splitter.get_exclude_content(self._TEST_PATH) self.assertEqual(self._SAMPLE_EXCLUDE_FOLDERS, exclude_folders) def test_remove_child_duplicate_sources_from_parent(self): """Test _remove_child_duplicate_sources_from_parent with conditions.""" child = mock.Mock() child.project_relative_path = 'c/d' root = 'a/b' parent_sources = ['a/b/d/e', 'a/b/e/f'] result = project_splitter._remove_child_duplicate_sources_from_parent( child, parent_sources, root) self.assertEqual(set(), result) parent_sources = ['a/b/c/d/e', 'a/b/e/f'] result = project_splitter._remove_child_duplicate_sources_from_parent( child, parent_sources, root) self.assertEqual({'a/b/c/d/e'}, result) @mock.patch('os.path.relpath') def test_get_rel_project_soong_paths(self, mock_rel): """Test _get_rel_project_soong_paths.""" mock_rel.return_value = 'out/soong' expected = [ 'out/soong/.intermediates/src1/', 'out/soong/.intermediates/src2/', 'out/soong/.intermediates/src2/src3/', 'out/soong/.intermediates/frameworks/base/' ] self.assertEqual( expected, self.split_projs._get_rel_project_soong_paths()) def test_get_real_dependencies_jars(self): """Test _get_real_dependencies_jars with conditions.""" expected = ['a/b/c/d'] self.assertEqual(expected, project_splitter._get_real_dependencies_jars( [], expected)) expected = ['a/b/c/d.jar'] self.assertEqual(expected, project_splitter._get_real_dependencies_jars( ['a/e'], expected)) expected = ['a/b/c/d.jar'] self.assertEqual([], project_splitter._get_real_dependencies_jars( ['a/b'], expected)) expected = ['a/b/c/d.srcjar'] self.assertEqual(expected, project_splitter._get_real_dependencies_jars( ['a/b'], expected)) expected = ['a/b/c/gen'] self.assertEqual(expected, project_splitter._get_real_dependencies_jars( ['a/b'], expected)) @mock.patch.object(common_util, 'get_android_root_dir') @mock.patch.object(common_util, 'get_soong_out_path') def test_get_permission_aapt2_rel_path(self, mock_soong, mock_root): """Test _get_permission_aapt2_rel_path.""" mock_soong.return_value = 'a/b/out/soong' mock_root.return_value = 'a/b' expected = ('out/soong/.intermediates/frameworks/base/core/res/' 'framework-res/android_common/gen/aapt2/R') self.assertEqual( expected, project_splitter._get_permission_aapt2_rel_path()) @mock.patch.object(common_util, 'get_android_root_dir') @mock.patch.object(common_util, 'get_soong_out_path') def test_get_permission_r_srcjar_rel_path(self, mock_soong, mock_root): """Test _get_permission_r_srcjar_rel_path.""" mock_soong.return_value = 'a/b/out/soong' mock_root.return_value = 'a/b' expected = ('out/soong/.intermediates/frameworks/base/core/res/' 'framework-res/android_common/gen/android/R.srcjar') self.assertEqual( expected, project_splitter._get_permission_r_srcjar_rel_path()) @mock.patch.object(project_splitter, '_get_permission_r_srcjar_rel_path') @mock.patch.object(project_splitter, '_get_permission_aapt2_rel_path') def test_remove_permission_definition_srcjar_path( self, mock_get_aapt2, mock_get_r_srcjar): """Test _remove_permission_definition_srcjar_path with conditions.""" expected_srcjars = [ 'other.srcjar', 'srcjar1.srcjar', 'srcjar2.srcjar', 'srcjar3.srcjar', ] mock_get_aapt2.return_value = 'none/aapt2/R' mock_get_r_srcjar.return_value = 'none.srcjar' self.split_projs._all_srcs['srcjar_path'] = expected_srcjars self.split_projs._remove_permission_definition_srcjar_path() srcjars = self.split_projs._all_srcs['srcjar_path'] self.assertEqual(sorted(list(srcjars)), expected_srcjars) expected_srcjars = [ 'other.srcjar', 'srcjar2.srcjar', 'srcjar3.srcjar', ] mock_get_r_srcjar.return_value = 'srcjar1.srcjar' self.split_projs._all_srcs['srcjar_path'] = expected_srcjars self.split_projs._remove_permission_definition_srcjar_path() srcjars = self.split_projs._all_srcs['srcjar_path'] self.assertEqual(sorted(list(srcjars)), expected_srcjars) @mock.patch('os.path.join') @mock.patch.object(common_util, 'unzip_file') @mock.patch('shutil.rmtree') @mock.patch('os.path.isfile') @mock.patch('os.path.isdir') def test_get_permission_defined_source_path( self, mock_is_dir, mock_is_file, mock_rmtree, mock_unzip, mock_join): """Test _get_permission_defined_source_path function.""" mock_is_dir.return_value = True self.split_projs._get_permission_defined_source_path() self.assertFalse(mock_is_file.called) self.assertFalse(mock_join.called) self.assertFalse(mock_rmtree.called) self.assertFalse(mock_unzip.called) mock_is_dir.return_value = False self.split_projs._get_permission_defined_source_path() self.assertTrue(mock_is_file.called) self.assertTrue(mock_join.called) self.assertFalse(mock_rmtree.called) self.assertTrue(mock_unzip.called) @mock.patch.object(common_util, 'unzip_file') @mock.patch('shutil.rmtree') @mock.patch('os.path.join') @mock.patch('os.path.dirname') @mock.patch('os.path.isdir') def test_unzip_all_scrjars( self, mock_is_dir, mock_dirname, mock_join, mock_rmtree, mock_unzip): """Test _unzip_all_scrjars function.""" mock_is_dir.return_value = True self.split_projs._unzip_all_scrjars() self.assertFalse(mock_dirname.called) self.assertFalse(mock_join.called) self.assertFalse(mock_rmtree.called) self.assertFalse(mock_unzip.called) if __name__ == '__main__': unittest.main()