1#!/usr/bin/env python3 2# 3# Copyright 2019, 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 aidegen_main.""" 18 19from __future__ import print_function 20 21import os 22import sys 23import unittest 24from unittest import mock 25 26from aidegen import aidegen_main 27from aidegen import constant 28from aidegen import unittest_constants 29from aidegen.lib import aidegen_metrics 30from aidegen.lib import common_util 31from aidegen.lib import eclipse_project_file_gen 32from aidegen.lib import errors 33from aidegen.lib import ide_util 34from aidegen.lib import module_info 35from aidegen.lib import native_util 36from aidegen.lib import native_module_info 37from aidegen.lib import native_project_info 38from aidegen.lib import project_config 39from aidegen.lib import project_file_gen 40from aidegen.lib import project_info 41from aidegen.vscode import vscode_workspace_file_gen 42 43 44# pylint: disable=protected-access 45# pylint: disable=invalid-name 46# pylint: disable=too-many-arguments 47# pylint: disable=too-many-function-args 48# pylint: disable=too-many-statements 49class AidegenMainUnittests(unittest.TestCase): 50 """Unit tests for aidegen_main.py""" 51 52 def _init_project_config(self, args): 53 """Initialize project configurations.""" 54 self.assertIsNotNone(args) 55 config = project_config.ProjectConfig(args) 56 config.init_environment() 57 58 def test_parse_args(self): 59 """Test _parse_args with different conditions.""" 60 args = aidegen_main._parse_args([]) 61 self.assertEqual(args.targets, ['']) 62 self.assertEqual(args.ide[0], 'j') 63 target = 'tradefed' 64 args = aidegen_main._parse_args([target]) 65 self.assertEqual(args.targets, [target]) 66 depth = '2' 67 args = aidegen_main._parse_args(['-d', depth]) 68 self.assertEqual(args.depth, int(depth)) 69 args = aidegen_main._parse_args(['-v']) 70 self.assertTrue(args.verbose) 71 args = aidegen_main._parse_args(['-v']) 72 self.assertTrue(args.verbose) 73 args = aidegen_main._parse_args(['-i', 's']) 74 self.assertEqual(args.ide[0], 's') 75 args = aidegen_main._parse_args(['-i', 'e']) 76 self.assertEqual(args.ide[0], 'e') 77 args = aidegen_main._parse_args(['-p', unittest_constants.TEST_MODULE]) 78 self.assertEqual(args.ide_installed_path, 79 unittest_constants.TEST_MODULE) 80 args = aidegen_main._parse_args(['-n']) 81 self.assertTrue(args.no_launch) 82 args = aidegen_main._parse_args(['-r']) 83 self.assertTrue(args.config_reset) 84 args = aidegen_main._parse_args(['-s']) 85 self.assertTrue(args.skip_build) 86 self.assertEqual(args.exclude_paths, None) 87 excludes = 'path/to/a', 'path/to/b' 88 args = aidegen_main._parse_args(['-e', excludes]) 89 self.assertEqual(args.exclude_paths, [excludes]) 90 91 @mock.patch.object(project_config.ProjectConfig, 'init_environment') 92 @mock.patch.object(project_config, 'ProjectConfig') 93 @mock.patch.object(project_file_gen.ProjectFileGenerator, 94 'generate_ide_project_files') 95 @mock.patch.object(eclipse_project_file_gen.EclipseConf, 96 'generate_ide_project_files') 97 def test_generate_project_files(self, mock_eclipse, mock_ide, mock_config, 98 mock_init): 99 """Test _generate_project_files with different conditions.""" 100 projects = ['module_a', 'module_v'] 101 args = aidegen_main._parse_args([projects, '-i', 'e']) 102 mock_init.return_value = None 103 self._init_project_config(args) 104 mock_config.ide_name = constant.IDE_ECLIPSE 105 aidegen_main._generate_project_files(projects) 106 self.assertTrue(mock_eclipse.called_with(projects)) 107 mock_config.ide_name = constant.IDE_ANDROID_STUDIO 108 aidegen_main._generate_project_files(projects) 109 self.assertTrue(mock_ide.called_with(projects)) 110 mock_config.ide_name = constant.IDE_INTELLIJ 111 aidegen_main._generate_project_files(projects) 112 self.assertTrue(mock_ide.called_with(projects)) 113 114 @mock.patch.object(aidegen_main, 'main_with_message') 115 @mock.patch.object(aidegen_main, 'main_without_message') 116 def test_main(self, mock_without, mock_with): 117 """Test main with conditions.""" 118 aidegen_main.main(['-s']) 119 self.assertEqual(mock_without.call_count, 1) 120 aidegen_main.main(['']) 121 self.assertEqual(mock_with.call_count, 1) 122 123 @mock.patch.object(aidegen_metrics, 'starts_asuite_metrics') 124 @mock.patch.object(project_config, 'is_whole_android_tree') 125 @mock.patch.object(aidegen_metrics, 'ends_asuite_metrics') 126 @mock.patch.object(aidegen_main, 'main_with_message') 127 def test_main_with_normal(self, mock_main, mock_ends_metrics, 128 mock_is_whole_tree, mock_starts_metrics): 129 """Test main with normal conditions.""" 130 aidegen_main.main(['-h']) 131 self.assertFalse(mock_main.called) 132 mock_is_whole_tree.return_value = True 133 aidegen_main.main(['']) 134 mock_starts_metrics.assert_called_with([constant.ANDROID_TREE]) 135 self.assertFalse(mock_ends_metrics.called) 136 aidegen_main.main(['-n']) 137 mock_ends_metrics.assert_called_with(constant.EXIT_CODE_NORMAL) 138 139 @mock.patch.object(aidegen_metrics, 'ends_asuite_metrics') 140 @mock.patch.object(aidegen_main, 'main_with_message') 141 def test_main_with_build_fail_errors(self, mock_main, mock_ends_metrics): 142 """Test main with raising build failure error conditions.""" 143 mock_main.side_effect = errors.BuildFailureError 144 with self.assertRaises(errors.BuildFailureError): 145 aidegen_main.main(['']) 146 _, exc_value, exc_traceback = sys.exc_info() 147 msg = str(exc_value) 148 mock_ends_metrics.assert_called_with( 149 constant.EXIT_CODE_AIDEGEN_EXCEPTION, exc_traceback, msg) 150 151 @mock.patch.object(aidegen_metrics, 'ends_asuite_metrics') 152 @mock.patch.object(aidegen_main, 'main_with_message') 153 def test_main_with_io_errors(self, mock_main, mock_ends_metrics): 154 """Test main with raising IO error conditions.""" 155 mock_main.side_effect = IOError 156 with self.assertRaises(IOError): 157 aidegen_main.main(['']) 158 _, exc_value, exc_traceback = sys.exc_info() 159 msg = str(exc_value) 160 mock_ends_metrics.assert_called_with(constant.EXIT_CODE_EXCEPTION, 161 exc_traceback, msg) 162 163 @mock.patch.object(aidegen_main, '_launch_ide') 164 @mock.patch.object(ide_util, 'get_ide_util_instance') 165 def test_launch_native_projects_without_ide_object( 166 self, mock_get_ide, mock_launch_ide): 167 """Test _launch_native_projects function without ide object.""" 168 target = 'libui' 169 args = aidegen_main._parse_args([target, '-i', 'e']) 170 aidegen_main._launch_native_projects(None, args, []) 171 self.assertFalse(mock_get_ide.called) 172 self.assertFalse(mock_launch_ide.called) 173 174 @mock.patch.object(aidegen_main, '_launch_ide') 175 @mock.patch.object(ide_util, 'get_ide_util_instance') 176 def test_launch_native_projects_with_ide_object( 177 self, mock_get_ide, mock_launch_ide): 178 """Test _launch_native_projects function without ide object.""" 179 target = 'libui' 180 args = aidegen_main._parse_args([target, '-i', 'e']) 181 ide_util_obj = 'some_obj' 182 mock_get_ide.return_value = None 183 aidegen_main._launch_native_projects(ide_util_obj, args, []) 184 self.assertTrue(mock_get_ide.called_with('c')) 185 self.assertFalse(mock_launch_ide.called) 186 mock_get_ide.reset_mock() 187 mock_launch_ide.reset_mock() 188 args.ide = ['j'] 189 aidegen_main._launch_native_projects(ide_util_obj, args, []) 190 self.assertTrue(mock_get_ide.called_with('c')) 191 self.assertFalse(mock_launch_ide.called) 192 mock_get_ide.reset_mock() 193 mock_launch_ide.reset_mock() 194 mock_get_ide.return_value = 'some_native_obj' 195 aidegen_main._launch_native_projects(ide_util_obj, args, []) 196 self.assertTrue(mock_get_ide.called_with('c')) 197 self.assertTrue(mock_launch_ide.called) 198 mock_get_ide.reset_mock() 199 mock_launch_ide.reset_mock() 200 args.ide = ['e'] 201 aidegen_main._launch_native_projects(ide_util_obj, args, []) 202 self.assertTrue(mock_get_ide.called_with('c')) 203 self.assertTrue(mock_launch_ide.called) 204 mock_get_ide.reset_mock() 205 mock_launch_ide.reset_mock() 206 args.ide = ['s'] 207 aidegen_main._launch_native_projects(ide_util_obj, args, []) 208 self.assertFalse(mock_get_ide.called) 209 self.assertTrue(mock_launch_ide.called) 210 211 @mock.patch('builtins.print') 212 def test_launch_ide(self, mock_print): 213 """Test _launch_ide function with config parameter.""" 214 mock_ide_util = mock.MagicMock() 215 mock_ide_util.launch_ide.return_value = None 216 mock_ide_util.config_ide.return_value = None 217 launch_path = '/test/launch/ide/method' 218 aidegen_main._launch_ide(mock_ide_util, launch_path) 219 self.assertTrue(mock_ide_util.config_ide.called) 220 self.assertTrue(mock_ide_util.launch_ide.called) 221 mock_print.return_value = None 222 223 @mock.patch('builtins.input') 224 def test_get_preferred_ide_from_user(self, mock_input): 225 """Test get_preferred_ide_from_user with different conditions.""" 226 test_data = [] 227 aidegen_main._get_preferred_ide_from_user(test_data) 228 self.assertFalse(mock_input.called) 229 mock_input.reset_mock() 230 231 test_data = ['One', 'Two', 'Three'] 232 mock_input.return_value = '3' 233 self.assertEqual('Three', aidegen_main._get_preferred_ide_from_user( 234 test_data)) 235 self.assertEqual(1, mock_input.call_count) 236 mock_input.reset_mock() 237 238 mock_input.side_effect = ['7', '5', '3'] 239 self.assertEqual('Three', aidegen_main._get_preferred_ide_from_user( 240 test_data)) 241 self.assertEqual(3, mock_input.call_count) 242 mock_input.reset_mock() 243 244 mock_input.side_effect = ('.', '7', 't', '5', '1') 245 self.assertEqual('One', aidegen_main._get_preferred_ide_from_user( 246 test_data)) 247 self.assertEqual(5, mock_input.call_count) 248 mock_input.reset_mock() 249 250 @mock.patch.object(project_config.ProjectConfig, 'init_environment') 251 @mock.patch('logging.warning') 252 @mock.patch.object(aidegen_main, '_launch_vscode') 253 @mock.patch.object(aidegen_main, '_launch_native_projects') 254 @mock.patch.object(native_util, 'generate_clion_projects') 255 @mock.patch.object(native_project_info.NativeProjectInfo, 256 'generate_projects') 257 @mock.patch.object(aidegen_main, '_create_and_launch_java_projects') 258 @mock.patch.object(aidegen_main, '_get_preferred_ide_from_user') 259 def test_launch_ide_by_module_contents(self, mock_choice, mock_j, 260 mock_c_prj, mock_genc, mock_c, 261 mock_vs, mock_log, mock_init): 262 """Test _launch_ide_by_module_contents with different conditions.""" 263 args = aidegen_main._parse_args(['', '-i', 's']) 264 mock_init.return_value = None 265 self._init_project_config(args) 266 ide_obj = 'ide_obj' 267 test_both = False 268 aidegen_main._launch_ide_by_module_contents(args, ide_obj, None, 269 None, test_both) 270 self.assertFalse(mock_vs.called) 271 self.assertTrue(mock_log.called) 272 self.assertFalse(mock_choice.called) 273 self.assertFalse(mock_choice.called) 274 self.assertFalse(mock_j.called) 275 self.assertFalse(mock_c_prj.called) 276 self.assertFalse(mock_genc.called) 277 self.assertFalse(mock_c.called) 278 279 test_both = True 280 aidegen_main._launch_ide_by_module_contents(args, ide_obj, None, 281 None, test_both) 282 self.assertTrue(mock_vs.called) 283 self.assertFalse(mock_j.called) 284 self.assertFalse(mock_genc.called) 285 self.assertFalse(mock_c.called) 286 mock_vs.reset_mock() 287 288 test_j = ['a', 'b', 'c'] 289 test_c = ['1', '2', '3'] 290 mock_choice.return_value = constant.JAVA 291 aidegen_main._launch_ide_by_module_contents(args, ide_obj, test_j, 292 test_c) 293 self.assertFalse(mock_vs.called) 294 self.assertTrue(mock_j.called) 295 self.assertFalse(mock_genc.called) 296 self.assertFalse(mock_c.called) 297 298 mock_vs.reset_mock() 299 mock_choice.reset_mock() 300 mock_c.reset_mock() 301 mock_genc.reset_mock() 302 mock_j.reset_mock() 303 mock_choice.return_value = constant.C_CPP 304 aidegen_main._launch_ide_by_module_contents(args, ide_obj, test_j, 305 test_c) 306 self.assertTrue(mock_c_prj.called) 307 self.assertFalse(mock_vs.called) 308 self.assertTrue(mock_genc.called) 309 self.assertTrue(mock_c.called) 310 self.assertFalse(mock_j.called) 311 312 mock_vs.reset_mock() 313 mock_choice.reset_mock() 314 mock_c.reset_mock() 315 mock_genc.reset_mock() 316 mock_j.reset_mock() 317 test_none = None 318 aidegen_main._launch_ide_by_module_contents(args, ide_obj, test_none, 319 test_c) 320 self.assertFalse(mock_vs.called) 321 self.assertTrue(mock_genc.called) 322 self.assertTrue(mock_c.called) 323 self.assertFalse(mock_j.called) 324 325 mock_vs.reset_mock() 326 mock_choice.reset_mock() 327 mock_c.reset_mock() 328 mock_genc.reset_mock() 329 mock_j.reset_mock() 330 aidegen_main._launch_ide_by_module_contents(args, ide_obj, test_j, 331 test_none) 332 self.assertFalse(mock_vs.called) 333 self.assertTrue(mock_j.called) 334 self.assertFalse(mock_c.called) 335 self.assertFalse(mock_genc.called) 336 337 args = aidegen_main._parse_args(['frameworks/base', '-i', 'c']) 338 mock_vs.reset_mock() 339 mock_choice.reset_mock() 340 mock_c.reset_mock() 341 mock_genc.reset_mock() 342 mock_c_prj.reset_mock() 343 mock_j.reset_mock() 344 aidegen_main._launch_ide_by_module_contents(args, ide_obj, test_j, 345 test_c) 346 self.assertFalse(mock_vs.called) 347 self.assertFalse(mock_choice.called) 348 self.assertFalse(mock_j.called) 349 self.assertTrue(mock_c.called) 350 self.assertTrue(mock_c_prj.called) 351 self.assertTrue(mock_genc.called) 352 353 args = aidegen_main._parse_args(['frameworks/base']) 354 mock_vs.reset_mock() 355 mock_choice.reset_mock() 356 mock_c.reset_mock() 357 mock_genc.reset_mock() 358 mock_c_prj.reset_mock() 359 mock_j.reset_mock() 360 os.environ[constant.AIDEGEN_TEST_MODE] = 'true' 361 aidegen_main._launch_ide_by_module_contents(args, None, test_j, test_c) 362 self.assertFalse(mock_vs.called) 363 self.assertFalse(mock_choice.called) 364 self.assertTrue(mock_j.called) 365 self.assertFalse(mock_c.called) 366 self.assertFalse(mock_c_prj.called) 367 self.assertFalse(mock_genc.called) 368 del os.environ[constant.AIDEGEN_TEST_MODE] 369 370 @mock.patch.object(aidegen_main, '_launch_ide') 371 @mock.patch.object(aidegen_main, '_generate_project_files') 372 @mock.patch.object(project_info.ProjectInfo, 'multi_projects_locate_source') 373 @mock.patch.object(project_info.ProjectInfo, 'generate_projects') 374 def test_create_and_launch_java_projects(self, mock_prj, mock_compile, 375 mock_gen_file, mock_launch): 376 """Test _create_and_launch_java_projects.""" 377 ide_obj = 'test_ide' 378 target = ['a', 'b'] 379 mock_prj_list = mock.MagicMock() 380 mock_prj_list.project_absolute_path = 'test_path' 381 prj = [mock_prj_list] 382 mock_prj.return_value = prj 383 aidegen_main._create_and_launch_java_projects(ide_obj, target) 384 self.assertTrue(mock_prj.called_with(target)) 385 self.assertTrue(mock_compile.called_with(prj)) 386 self.assertTrue(mock_gen_file.called_with(prj)) 387 self.assertTrue(mock_launch.called_with(ide_obj)) 388 mock_launch.reset_mock() 389 390 aidegen_main._create_and_launch_java_projects(None, target) 391 self.assertFalse(mock_launch.called) 392 393 @mock.patch.object(aidegen_main, '_launch_ide') 394 @mock.patch.object(vscode_workspace_file_gen, 395 'generate_code_workspace_file') 396 @mock.patch.object(common_util, 'get_related_paths') 397 def test_launch_vscode_without_ide_object( 398 self, mock_get_rel, mock_gen_code, mock_launch_ide): 399 """Test _launch_vscode function without ide object.""" 400 mock_get_rel.return_value = 'rel', 'abs' 401 aidegen_main._launch_vscode(None, mock.Mock(), ['Settings'], []) 402 self.assertTrue(mock_get_rel.called) 403 self.assertTrue(mock_gen_code.called) 404 self.assertFalse(mock_launch_ide.called) 405 406 @mock.patch.object(aidegen_main, '_launch_ide') 407 @mock.patch.object(vscode_workspace_file_gen, 408 'generate_code_workspace_file') 409 @mock.patch.object(common_util, 'get_related_paths') 410 def test_launch_vscode_with_ide_object( 411 self, mock_get_rel, mock_gen_code, mock_get_ide): 412 """Test _launch_vscode function with ide object.""" 413 mock_get_rel.return_value = 'rel', 'abs' 414 aidegen_main._launch_vscode(mock.Mock(), mock.Mock(), ['Settings'], []) 415 self.assertTrue(mock_get_rel.called) 416 self.assertTrue(mock_gen_code.called) 417 self.assertTrue(mock_get_ide.called) 418 419 @mock.patch.object(aidegen_main, '_launch_vscode') 420 @mock.patch.object(aidegen_main, '_launch_ide') 421 @mock.patch.object(vscode_workspace_file_gen, 422 'generate_code_workspace_file') 423 @mock.patch.object(common_util, 'get_related_paths') 424 def test_launch_vscode_with_both_languages( 425 self, mock_get_rel, mock_gen_code, mock_get_ide, mock_vscode): 426 """Test _launch_vscode function without ide object.""" 427 mock_get_rel.return_value = 'rel', 'abs' 428 aidegen_main._launch_vscode(None, mock.Mock(), ['Settings'], [], True) 429 self.assertFalse(mock_get_rel.called) 430 self.assertFalse(mock_gen_code.called) 431 self.assertFalse(mock_get_ide.called) 432 self.assertTrue(mock_vscode.called) 433 434 @mock.patch.object(aidegen_main, '_launch_ide_by_module_contents') 435 @mock.patch.object(native_util, 'get_native_and_java_projects') 436 @mock.patch.object(native_module_info, 'NativeModuleInfo') 437 @mock.patch.object(module_info, 'AidegenModuleInfo') 438 @mock.patch.object(ide_util, 'get_ide_util_instance') 439 @mock.patch.object(project_config, 'ProjectConfig') 440 def test_aidegen_main(self, mock_config, mock_get_ide, mock_mod_info, 441 mock_native, mock_get_project, mock_launch_ide): 442 """Test aidegen_main function with conditions.""" 443 target = 'Settings' 444 args = aidegen_main._parse_args([target, '-i', 'v']) 445 config = mock.Mock() 446 config.targets = [target] 447 config.ide_name = constant.IDE_VSCODE 448 mock_config.return_value = config 449 ide = mock.Mock() 450 mock_get_ide.return_value = ide 451 mock_get_project.return_value = config.targets, [] 452 aidegen_main.aidegen_main(args) 453 self.assertTrue(mock_config.called) 454 self.assertTrue(mock_get_ide.called) 455 self.assertTrue(mock_mod_info.called) 456 self.assertTrue(mock_native.called) 457 self.assertTrue(mock_get_project.called) 458 mock_launch_ide.assert_called_with(args, ide, config.targets, [], True) 459 460 mock_config.mock_reset() 461 mock_get_ide.mock_reset() 462 mock_mod_info.mock_reset() 463 mock_native.mock_reset() 464 mock_get_project.mock_reset() 465 mock_launch_ide.mock_reset() 466 467 args = aidegen_main._parse_args([target]) 468 config.ide_name = constant.IDE_INTELLIJ 469 aidegen_main.aidegen_main(args) 470 self.assertTrue(mock_config.called) 471 self.assertTrue(mock_get_ide.called) 472 self.assertTrue(mock_mod_info.called) 473 self.assertTrue(mock_native.called) 474 self.assertTrue(mock_get_project.called) 475 mock_launch_ide.assert_called_with(args, ide, config.targets, [], False) 476 477 478if __name__ == '__main__': 479 unittest.main() 480