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"""Functional test for aidegen project files.""" 18 19from __future__ import absolute_import 20from __future__ import print_function 21 22import argparse 23import functools 24import itertools 25import json 26import logging 27import os 28import subprocess 29import sys 30import xml.etree.ElementTree 31import xml.parsers.expat 32 33from aidegen import aidegen_main 34from aidegen import constant 35from aidegen.lib import clion_project_file_gen 36# pylint: disable=no-name-in-module 37from aidegen.lib import common_util 38from aidegen.lib import errors 39from aidegen.lib import module_info_util 40from aidegen.lib import project_config 41from aidegen.lib import project_file_gen 42 43from atest import module_info 44 45_PRODUCT_DIR = '$PROJECT_DIR$' 46_ROOT_DIR = os.path.join(common_util.get_android_root_dir(), 47 'tools/asuite/aidegen_functional_test') 48_TEST_DATA_PATH = os.path.join(_ROOT_DIR, 'test_data') 49_VERIFY_COMMANDS_JSON = os.path.join(_TEST_DATA_PATH, 'verify_commands.json') 50_GOLDEN_SAMPLES_JSON = os.path.join(_TEST_DATA_PATH, 'golden_samples.json') 51_VERIFY_BINARY_JSON = os.path.join(_TEST_DATA_PATH, 'verify_binary_upload.json') 52_VERIFY_PRESUBMIT_JSON = os.path.join(_TEST_DATA_PATH, 'verify_presubmit.json') 53_ANDROID_COMMON = 'android_common' 54_LINUX_GLIBC_COMMON = 'linux_glibc_common' 55_SRCS = 'srcs' 56_JARS = 'jars' 57_URL = 'url' 58_TEST_ERROR = 'AIDEGen functional test error: {}-{} is different.' 59_MSG_NOT_IN_PROJECT_FILE = ('{} is expected, but not found in the created ' 60 'project file: {}') 61_MSG_NOT_IN_SAMPLE_DATA = ('{} is unexpected, but found in the created project ' 62 'file: {}') 63_ALL_PASS = 'All tests passed!' 64_GIT_COMMIT_ID_JSON = os.path.join( 65 _TEST_DATA_PATH, 'baseline_code_commit_id.json') 66_GIT = 'git' 67_CHECKOUT = 'checkout' 68_BRANCH = 'branch' 69_COMMIT = 'commit' 70_LOG = 'log' 71_ALL = '--all' 72_COMMIT_ID_NOT_EXIST_ERROR = ('Commit ID: {} does not exist in path: {}. ' 73 'Please use "git log" command to check if it ' 74 'exists. If it does not, try to update your ' 75 'source files to the latest version or do not ' 76 'use "repo init --depth=1" command.') 77_GIT_LOG_ERROR = 'Command "git log -n 1" failed.' 78_BE_REPLACED = '${config.X86_64GccRoot}' 79_TO_REPLACE = 'prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9' 80 81 82def _parse_args(args): 83 """Parse command line arguments. 84 85 Args: 86 args: A list of arguments. 87 88 Returns: 89 An argparse.Namespace object holding parsed args. 90 """ 91 parser = argparse.ArgumentParser( 92 description=__doc__, 93 formatter_class=argparse.RawDescriptionHelpFormatter, 94 usage='aidegen_functional_test [-c | -u | -b | -a] -v -r') 95 group = parser.add_mutually_exclusive_group() 96 parser.required = False 97 parser.add_argument( 98 'targets', 99 type=str, 100 nargs='*', 101 default=[''], 102 help='Android module name or path.e.g. frameworks/base') 103 group.add_argument( 104 '-c', 105 '--create-sample', 106 action='store_true', 107 dest='create_sample', 108 help=('Create aidegen project files and write data to sample json file ' 109 'for aidegen_functional_test to compare.')) 110 parser.add_argument( 111 '-v', 112 '--verbose', 113 action='store_true', 114 help='Show DEBUG level logging.') 115 parser.add_argument( 116 '-r', 117 '--remove_bp_json', 118 action='store_true', 119 help='Remove module_bp_java_deps.json for each use case test.') 120 parser.add_argument( 121 '-m', 122 '--make_clean', 123 action='store_true', 124 help=('Make clean before testing to create a clean environment, the ' 125 'aidegen_functional_test can run only once if users command it.')) 126 group.add_argument( 127 '-u', 128 '--use_cases', 129 action='store_true', 130 dest='use_cases_verified', 131 help='Verify various use cases of executing aidegen.') 132 group.add_argument( 133 '-b', 134 action='store_true', 135 dest='binary_upload_verified', 136 help=('Verify aidegen\'s use cases by executing different aidegen ' 137 'commands.')) 138 group.add_argument( 139 '-p', 140 action='store_true', 141 dest='binary_presubmit_verified', 142 help=('Verify aidegen\'s tool in presubmit test by executing' 143 'different aidegen commands.')) 144 group.add_argument( 145 '-a', 146 '--test-all', 147 action='store_true', 148 dest='test_all_samples', 149 help='Test all modules listed in module-info.json.') 150 group.add_argument( 151 '-n', 152 '--compare-sample-native', 153 action='store_true', 154 dest='compare_sample_native', 155 help=('Compare if sample native project file is the same as generated ' 156 'by the build system.')) 157 return parser.parse_args(args) 158 159 160def _import_project_file_xml_etree(filename): 161 """Import iml project file and load its data into a dictionary. 162 163 Args: 164 filename: The input project file name. 165 166 Returns: 167 A dictionary contains dependent files' data of project file's contents. 168 The samples are like: 169 "srcs": [ 170 ... 171 "file://$PROJECT_DIR$/frameworks/base/cmds/am/src", 172 "file://$PROJECT_DIR$/frameworks/base/cmds/appwidget/src", 173 ... 174 ] 175 "jars": [ 176 ... 177 "jar://$PROJECT_DIR$/out/host/common/obj/**/classes-header.jar!/" 178 ... 179 ] 180 181 Raises: 182 EnvironmentError and xml parsing or format errors. 183 """ 184 data = {} 185 try: 186 tree = xml.etree.ElementTree.parse(filename) 187 data[_SRCS] = [] 188 root = tree.getroot() 189 for element in root.iter('sourceFolder'): 190 src = element.get(_URL).replace(common_util.get_android_root_dir(), 191 _PRODUCT_DIR) 192 data[_SRCS].append(src) 193 data[_JARS] = [] 194 for element in root.iter('root'): 195 jar = element.get(_URL).replace(common_util.get_android_root_dir(), 196 _PRODUCT_DIR) 197 data[_JARS].append(jar) 198 except (EnvironmentError, ValueError, LookupError, 199 xml.parsers.expat.ExpatError) as err: 200 print("{0}: import error: {1}".format(os.path.basename(filename), err)) 201 raise 202 return data 203 204 205def _get_project_file_names(abs_path): 206 """Get project file name and depenencies name by relative path. 207 208 Args: 209 abs_path: an absolute module's path. 210 211 Returns: 212 file_name: a string of the project file name. 213 dep_name: a string of the merged project and dependencies file's name, 214 e.g., frameworks-dependencies.iml. 215 """ 216 # pylint: disable=maybe-no-member 217 code_name = project_file_gen.ProjectFileGenerator.get_unique_iml_name( 218 abs_path) 219 file_name = ''.join([code_name, '.iml']) 220 dep_name = ''.join([constant.KEY_DEPENDENCIES, '.iml']) 221 return file_name, dep_name 222 223 224def _get_unique_module_name(rel_path, filename): 225 """Get a unique project file name or dependencies name by relative path. 226 227 Args: 228 rel_path: a relative module's path to aosp root path. 229 filename: the file name to be generated in module_in type file name. 230 231 Returns: 232 A string, the unique file name for the whole module-info.json. 233 """ 234 code_names = rel_path.split(os.sep) 235 code_names[-1] = filename 236 return '-'.join(code_names) 237 238 239def _get_git_current_commit_id(abs_path): 240 """Get target's git checkout command list. 241 242 When we run command 'git log -n 1' and get the top first git log record, the 243 commit id is next to the specific word 'commit'. 244 245 Args: 246 abs_path: a string of the absolute path of the target branch. 247 248 Return: 249 The current git commit id. 250 251 Raises: 252 Call subprocess.check_output cause subprocess.CalledProcessError. 253 """ 254 cwd = os.getcwd() 255 os.chdir(abs_path) 256 git_log_cmds = [_GIT, _LOG, '-n', '1'] 257 try: 258 out_put = subprocess.check_output(git_log_cmds).decode("utf-8") 259 except subprocess.CalledProcessError: 260 logging.error(_GIT_LOG_ERROR) 261 raise 262 finally: 263 os.chdir(cwd) 264 com_list = out_put.split() 265 return com_list[com_list.index(_COMMIT) + 1] 266 267 268def _get_commit_id_dictionary(): 269 """Get commit id from dictionary of key, value 'module': 'commit id'.""" 270 data_id_dict = {} 271 with open(_GIT_COMMIT_ID_JSON, 'r') as jsfile: 272 data_id_dict = json.load(jsfile) 273 return data_id_dict 274 275 276def _git_checkout_commit_id(abs_path, commit_id): 277 """Command to checkout specific commit id. 278 279 Change directory to the module's absolute path which users want to get its 280 specific commit id. 281 282 Args: 283 abs_path: the absolute path of the target branch. E.g., abs_path/.git 284 commit_id: the commit id users want to checkout. 285 286 Raises: 287 Call git checkout commit id failed, raise errors.CommitIDNotExistError. 288 """ 289 git_chekout_cmds = [_GIT, _CHECKOUT, commit_id] 290 cwd = os.getcwd() 291 try: 292 os.chdir(abs_path) 293 subprocess.check_output(git_chekout_cmds) 294 except subprocess.CalledProcessError: 295 err = _COMMIT_ID_NOT_EXIST_ERROR.format(commit_id, abs_path) 296 logging.error(err) 297 raise errors.CommitIDNotExistError(err) 298 finally: 299 os.chdir(cwd) 300 301 302def _git_checkout_target_commit_id(target, commit_id): 303 """Command to checkout target commit id. 304 305 Switch code base to specific commit id which is kept in data_id_dict with 306 target: commit_id as key: value. If the data is missing in data_id_dict, the 307 target isn't a selected golden sample raise error for it. 308 309 Args: 310 target: the string of target's module name or module path to checkout 311 the relevant git to its specific commit id. 312 commit_id: a string represent target's specific commit id. 313 314 Returns: 315 current_commit_id: the current commit id of the target which should be 316 switched back to. 317 """ 318 atest_module_info = module_info.ModuleInfo() 319 _, abs_path = common_util.get_related_paths(atest_module_info, target) 320 current_commit_id = _get_git_current_commit_id(abs_path) 321 _git_checkout_commit_id(abs_path, commit_id) 322 return current_commit_id 323 324 325def _checkout_baseline_code_to_spec_commit_id(): 326 """Get a dict of target, commit id listed in baseline_code_commit_id.json. 327 328 To make sure all samples run on the same environment, we need to keep all 329 the baseline code in a specific commit id. For example, all samples should 330 be created in the same specific commit id of the baseline code 331 'frameworks/base' for comparison except 'frameworks/base' itself. 332 333 Returns: 334 A dictionary contains target, specific and current commit id. 335 """ 336 spec_and_cur_commit_id_dict = {} 337 data_id_dict = _get_commit_id_dictionary() 338 for target in data_id_dict: 339 commit_id = data_id_dict.get(target, '') 340 current_commit_id = _git_checkout_target_commit_id(target, commit_id) 341 spec_and_cur_commit_id_dict[target] = {} 342 spec_and_cur_commit_id_dict[target]['current'] = current_commit_id 343 return spec_and_cur_commit_id_dict 344 345 346def _generate_target_real_iml_data(target): 347 """Generate single target's real iml file content's data. 348 349 Args: 350 target: Android module name or path to be create iml data. 351 352 Returns: 353 data: A dictionary contains key: unique file name and value: iml 354 content. 355 """ 356 data = {} 357 try: 358 aidegen_main.main([target, '-s', '-n', '-v']) 359 except (errors.FakeModuleError, 360 errors.ProjectOutsideAndroidRootError, 361 errors.ProjectPathNotExistError, 362 errors.NoModuleDefinedInModuleInfoError) as err: 363 logging.error(str(err)) 364 return data 365 366 atest_module_info = module_info.ModuleInfo() 367 rel_path, abs_path = common_util.get_related_paths(atest_module_info, 368 target) 369 for filename in iter(_get_project_file_names(abs_path)): 370 real_iml_file = os.path.join(abs_path, filename) 371 item_name = _get_unique_module_name(rel_path, filename) 372 data[item_name] = _import_project_file_xml_etree(real_iml_file) 373 return data 374 375 376def _generate_sample_json(test_list): 377 """Generate sample iml data. 378 379 We use all baseline code samples on the version of their own specific commit 380 id which is kept in _GIT_COMMIT_ID_JSON file. We need to switch back to 381 their current commit ids after generating golden samples' data. 382 383 Args: 384 test_list: a list of module name and module path. 385 386 Returns: 387 data: a dictionary contains dependent files' data of project file's 388 contents. 389 The sample is like: 390 "frameworks-base.iml": { 391 "srcs": [ 392 .... 393 "file://$PROJECT_DIR$/frameworks/base/cmds/am/src", 394 "file://$PROJECT_DIR$/frameworks/base/cmds/appwidget/src", 395 .... 396 ], 397 "jars": [ 398 .... 399 "jar://$PROJECT_DIR$/out/target/common/**/aapt2.srcjar!/", 400 .... 401 ] 402 } 403 """ 404 data = {} 405 spec_and_cur_commit_id_dict = _checkout_baseline_code_to_spec_commit_id() 406 for target in test_list: 407 data.update(_generate_target_real_iml_data(target)) 408 atest_module_info = module_info.ModuleInfo() 409 for target in spec_and_cur_commit_id_dict: 410 _, abs_path = common_util.get_related_paths(atest_module_info, target) 411 _git_checkout_commit_id( 412 abs_path, spec_and_cur_commit_id_dict[target]['current']) 413 return data 414 415 416def _create_some_sample_json_file(targets): 417 """Write some samples' iml data into a json file. 418 419 Args: 420 targets: Android module name or path to be create iml data. 421 422 linked_function: _generate_sample_json() 423 """ 424 data = _generate_sample_json(targets) 425 data_sample = {} 426 with open(_GOLDEN_SAMPLES_JSON, 'r') as infile: 427 try: 428 data_sample = json.load(infile) 429 # pylint: disable=maybe-no-member 430 except json.JSONDecodeError as err: 431 print("Json decode error: {}".format(err)) 432 data_sample = {} 433 data_sample.update(data) 434 with open(_GOLDEN_SAMPLES_JSON, 'w') as outfile: 435 json.dump(data_sample, outfile, indent=4, sort_keys=False) 436 437 438def test_samples(func): 439 """Decorate a function to deal with preparing and verifying staffs of it. 440 441 Args: 442 func: a function is to be compared its iml data with the json file's 443 data. 444 445 Returns: 446 The wrapper function. 447 """ 448 449 @functools.wraps(func) 450 def wrapper(*args, **kwargs): 451 """A wrapper function.""" 452 453 test_successful = True 454 with open(_GOLDEN_SAMPLES_JSON, 'r') as outfile: 455 data_sample = json.load(outfile) 456 457 data_real = func(*args, **kwargs) 458 459 for name in data_real: 460 for item in [_SRCS, _JARS]: 461 s_items = data_sample[name][item] 462 r_items = data_real[name][item] 463 if set(s_items) != set(r_items): 464 diff_iter = _compare_content(name, item, s_items, r_items) 465 if diff_iter: 466 print('\n{} {}'.format( 467 common_util.COLORED_INFO('Test error:'), 468 _TEST_ERROR.format(name, item))) 469 print('{} {} contents are different:'.format( 470 name, item)) 471 for diff in diff_iter: 472 print(diff) 473 test_successful = False 474 if test_successful: 475 print(common_util.COLORED_PASS(_ALL_PASS)) 476 return test_successful 477 478 return wrapper 479 480 481@test_samples 482def _test_some_sample_iml(targets=None): 483 """Compare with sample iml's data to assure the project's contents is right. 484 485 Args: 486 targets: Android module name or path to be create iml data. 487 """ 488 if targets: 489 return _generate_sample_json(targets) 490 return _generate_sample_json(_get_commit_id_dictionary().keys()) 491 492 493@test_samples 494def _test_all_samples_iml(): 495 """Compare all imls' data with all samples' data. 496 497 It's to make sure each iml's contents is right. The function is implemented 498 but hasn't been used yet. 499 """ 500 all_module_list = module_info.ModuleInfo().name_to_module_info.keys() 501 return _generate_sample_json(all_module_list) 502 503 504def _compare_content(module_name, item_type, s_items, r_items): 505 """Compare src or jar files' data of two dictionaries. 506 507 Args: 508 module_name: the test module name. 509 item_type: the type is src or jar. 510 s_items: sample jars' items. 511 r_items: real jars' items. 512 513 Returns: 514 An iterator of not equal sentences after comparison. 515 """ 516 if item_type == _SRCS: 517 cmp_iter1 = _compare_srcs_content(module_name, s_items, r_items, 518 _MSG_NOT_IN_PROJECT_FILE) 519 cmp_iter2 = _compare_srcs_content(module_name, r_items, s_items, 520 _MSG_NOT_IN_SAMPLE_DATA) 521 else: 522 cmp_iter1 = _compare_jars_content(module_name, s_items, r_items, 523 _MSG_NOT_IN_PROJECT_FILE) 524 cmp_iter2 = _compare_jars_content(module_name, r_items, s_items, 525 _MSG_NOT_IN_SAMPLE_DATA) 526 return itertools.chain(cmp_iter1, cmp_iter2) 527 528 529def _compare_srcs_content(module_name, s_items, r_items, msg): 530 """Compare src or jar files' data of two dictionaries. 531 532 Args: 533 module_name: the test module name. 534 s_items: sample jars' items. 535 r_items: real jars' items. 536 msg: the message will be written into log file. 537 538 Returns: 539 An iterator of not equal sentences after comparison. 540 """ 541 for sample in s_items: 542 if sample not in r_items: 543 yield msg.format(sample, module_name) 544 545 546def _compare_jars_content(module_name, s_items, r_items, msg): 547 """Compare src or jar files' data of two dictionaries. 548 549 AIDEGen treats the jars in folder names 'linux_glib_common' and 550 'android_common' as the same content. If the paths are different only 551 because of these two names, we ignore it. 552 553 Args: 554 module_name: the test module name. 555 s_items: sample jars' items. 556 r_items: real jars' items. 557 msg: the message will be written into log file. 558 559 Returns: 560 An iterator of not equal sentences after comparison. 561 """ 562 for sample in s_items: 563 if sample not in r_items: 564 lnew = sample 565 if constant.LINUX_GLIBC_COMMON in sample: 566 lnew = sample.replace(constant.LINUX_GLIBC_COMMON, 567 constant.ANDROID_COMMON) 568 else: 569 lnew = sample.replace(constant.ANDROID_COMMON, 570 constant.LINUX_GLIBC_COMMON) 571 if not lnew in r_items: 572 yield msg.format(sample, module_name) 573 574 575# pylint: disable=broad-except 576# pylint: disable=eval-used 577@common_util.back_to_cwd 578@common_util.time_logged 579def _verify_aidegen(verified_file_path, forced_remove_bp_json, 580 is_presubmit=False): 581 """Verify various use cases of executing aidegen. 582 583 There are two types of running commands: 584 1. Use 'eval' to run the commands for present codes in aidegen_main.py, 585 such as: 586 aidegen_main.main(['tradefed', '-n', '-v']) 587 2. Use 'subprocess.check_call' to run the commands for the binary codes of 588 aidegen such as: 589 aidegen tradefed -n -v 590 591 Remove module_bp_java_deps.json in the beginning of running use cases. If 592 users need to remove module_bp_java_deps.json between each use case they 593 can set forced_remove_bp_json true. 594 595 Args: 596 verified_file_path: The json file path to be verified. 597 forced_remove_bp_json: Remove module_bp_java_deps.json for each use case 598 test. 599 600 Raises: 601 There are two type of exceptions: 602 1. aidegen.lib.errors for projects' or modules' issues such as, 603 ProjectPathNotExistError. 604 2. Any exceptions other than aidegen.lib.errors such as, 605 subprocess.CalledProcessError. 606 """ 607 bp_json_path = common_util.get_blueprint_json_path( 608 constant.BLUEPRINT_JAVA_JSONFILE_NAME) 609 use_eval = (verified_file_path == _VERIFY_COMMANDS_JSON) 610 try: 611 with open(verified_file_path, 'r') as jsfile: 612 data = json.load(jsfile) 613 except IOError as err: 614 raise errors.JsonFileNotExistError( 615 '%s does not exist, error: %s.' % (verified_file_path, err)) 616 617 if not is_presubmit: 618 _compare_sample_native_content() 619 620 os.chdir(common_util.get_android_root_dir()) 621 for use_case in data: 622 print('Use case "{}" is running.'.format(use_case)) 623 if forced_remove_bp_json and os.path.exists(bp_json_path): 624 os.remove(bp_json_path) 625 for cmd in data[use_case]: 626 print('Command "{}" is running.'.format(cmd)) 627 try: 628 if use_eval: 629 eval(cmd) 630 else: 631 subprocess.check_call(cmd, shell=True) 632 except (errors.ProjectOutsideAndroidRootError, 633 errors.ProjectPathNotExistError, 634 errors.NoModuleDefinedInModuleInfoError, 635 errors.IDENotExistError) as err: 636 print('"{}" raises error: {}.'.format(use_case, err)) 637 continue 638 except BaseException: 639 exc_type, _, _ = sys.exc_info() 640 print('"{}.{}" command {}.'.format( 641 use_case, cmd, common_util.COLORED_FAIL('executes failed'))) 642 raise BaseException( 643 'Unexpected command "{}" exception: {}.'.format( 644 use_case, exc_type)) 645 print('"{}" command {}!'.format( 646 use_case, common_util.COLORED_PASS('test passed'))) 647 print(common_util.COLORED_PASS(_ALL_PASS)) 648 649 650@common_util.back_to_cwd 651def _make_clean(): 652 """Make a command to clean out folder for a pure environment to test. 653 654 Raises: 655 Call subprocess.check_call to execute 656 'build/soong/soong_ui.bash --make-mode clean' and cause 657 subprocess.CalledProcessError. 658 """ 659 try: 660 os.chdir(common_util.get_android_root_dir()) 661 subprocess.check_call( 662 ['build/soong/soong_ui.bash --make-mode clean', '-j'], 663 shell=True) 664 except subprocess.CalledProcessError: 665 print('"build/soong/soong_ui.bash --make-mode clean" command failed.') 666 raise 667 668 669def _read_file_content(path): 670 """Read file's content. 671 672 Args: 673 path: Path of input file. 674 675 Returns: 676 A list of content strings. 677 """ 678 with open(path, encoding='utf8') as template: 679 contents = [] 680 for cnt in template: 681 if cnt.startswith('#'): 682 continue 683 contents.append(cnt.rstrip()) 684 return contents 685 686 687# pylint: disable=protected-access 688def _compare_sample_native_content(): 689 """Compares 'libui' sample module's project file. 690 691 Compares 'libui' sample module's project file generated by AIDEGen with that 692 generated by the soong build system. Check if their contents are the same. 693 There should be only one different: 694 ${config.X86_64GccRoot} # in the soong build sytem 695 becomes 696 prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9 # in AIDEGen 697 """ 698 target_arch_variant = 'x86_64' 699 env_on = { 700 'TARGET_PRODUCT': 'aosp_x86_64', 701 'TARGET_BUILD_VARIANT': 'eng', 702 'TARGET_ARCH_VARIANT': target_arch_variant, 703 'SOONG_COLLECT_JAVA_DEPS': 'true', 704 'SOONG_GEN_CMAKEFILES': '1', 705 'SOONG_COLLECT_CC_DEPS': '1' 706 } 707 708 try: 709 project_config.ProjectConfig( 710 aidegen_main._parse_args(['-n', '-v'])).init_environment() 711 module_info_util.generate_merged_module_info(env_on) 712 cc_path = os.path.join(common_util.get_soong_out_path(), 713 constant.BLUEPRINT_CC_JSONFILE_NAME) 714 mod_name = 'libui' 715 mod_info = common_util.get_json_dict(cc_path)['modules'][mod_name] 716 if mod_info: 717 clion_project_file_gen.CLionProjectFileGenerator( 718 mod_info).generate_cmakelists_file() 719 out_dir = os.path.join(common_util.get_android_root_dir(), 720 common_util.get_android_out_dir(), 721 constant.RELATIVE_NATIVE_PATH, 722 mod_info['path'][0]) 723 content1 = _read_file_content(os.path.join( 724 out_dir, mod_name, constant.CLION_PROJECT_FILE_NAME)) 725 cc_file_name = ''.join( 726 [mod_name, '-', target_arch_variant, '-android']) 727 cc_file_path = os.path.join( 728 out_dir, cc_file_name, constant.CLION_PROJECT_FILE_NAME) 729 content2 = _read_file_content(cc_file_path) 730 same = True 731 for lino, (cnt1, cnt2) in enumerate( 732 zip(content1, content2), start=1): 733 if _BE_REPLACED in cnt2: 734 cnt2 = cnt2.replace(_BE_REPLACED, _TO_REPLACE) 735 if cnt1 != cnt2: 736 print('Contents {} and {} are different in line:{}.'.format( 737 cnt1, cnt2, lino)) 738 same = False 739 if same: 740 print('Files {} and {} are the same.'.format( 741 mod_name, cc_file_name)) 742 except errors.BuildFailureError: 743 print('Compare native content failed.') 744 745 746def main(argv): 747 """Main entry. 748 749 1. Create the iml file data of each module in module-info.json and write it 750 into single_module.json. 751 2. Verify every use case of AIDEGen. 752 3. Compare all or some iml project files' data to the data recorded in 753 single_module.json. 754 755 Args: 756 argv: A list of system arguments. 757 """ 758 args = _parse_args(argv) 759 common_util.configure_logging(args.verbose) 760 os.environ[constant.AIDEGEN_TEST_MODE] = 'true' 761 762 if args.make_clean: 763 _make_clean() 764 765 if args.create_sample: 766 _create_some_sample_json_file(args.targets) 767 elif args.use_cases_verified: 768 _verify_aidegen(_VERIFY_COMMANDS_JSON, args.remove_bp_json) 769 elif args.binary_upload_verified: 770 _verify_aidegen(_VERIFY_BINARY_JSON, args.remove_bp_json) 771 elif args.binary_presubmit_verified: 772 _verify_aidegen(_VERIFY_PRESUBMIT_JSON, args.remove_bp_json, True) 773 elif args.test_all_samples: 774 _test_all_samples_iml() 775 elif args.compare_sample_native: 776 _compare_sample_native_content() 777 else: 778 if not args.targets[0]: 779 _test_some_sample_iml() 780 else: 781 _test_some_sample_iml(args.targets) 782 783 del os.environ[constant.AIDEGEN_TEST_MODE] 784 785 786if __name__ == '__main__': 787 main(sys.argv[1:]) 788