1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# 4# Copyright (c) 2021-2022 Huawei Device Co., Ltd. 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 17from glob import glob 18from os import path 19from enum import Enum 20import argparse 21import fnmatch 22import multiprocessing 23import os 24import re 25import shutil 26import subprocess 27import sys 28 29 30def is_directory(parser, arg): 31 if not path.isdir(arg): 32 parser.error("The directory '%s' does not exist" % arg) 33 34 return path.abspath(arg) 35 36 37def is_file(parser, arg): 38 if not path.isfile(arg): 39 parser.error("The file '%s' does not exist" % arg) 40 41 return path.abspath(arg) 42 43def prepare_tsc_testcases(test_root): 44 third_party_tsc = path.join(test_root, "TypeScript") 45 ohos_third_party_tsc = path.join(test_root, "../../../../third_party/typescript") 46 47 if not path.isdir(third_party_tsc): 48 if (path.isdir(ohos_third_party_tsc)): 49 return path.abspath(ohos_third_party_tsc) 50 subprocess.run( 51 f"git clone https://gitee.com/openharmony/third_party_typescript.git {third_party_tsc}", 52 shell=True, 53 stdout=subprocess.DEVNULL, 54 ) 55 else: 56 subprocess.run( 57 f"cd {third_party_tsc} && git clean -f > /dev/null 2>&1", 58 shell=True, 59 stdout=subprocess.DEVNULL, 60 ) 61 return third_party_tsc 62 63def check_timeout(value): 64 ivalue = int(value) 65 if ivalue <= 0: 66 raise argparse.ArgumentTypeError( 67 "%s is an invalid timeout value" % value) 68 return ivalue 69 70 71def get_args(): 72 parser = argparse.ArgumentParser(description="Regression test runner") 73 parser.add_argument( 74 'build_dir', type=lambda arg: is_directory(parser, arg), 75 help='panda build directory') 76 parser.add_argument( 77 '--error', action='store_true', dest='error', default=False, 78 help='capture stderr') 79 parser.add_argument( 80 '--abc-to-asm', action='store_true', dest='abc_to_asm', 81 default=False, help='run abc2asm tests') 82 parser.add_argument( 83 '--regression', '-r', action='store_true', dest='regression', 84 default=False, help='run regression tests') 85 parser.add_argument( 86 '--compiler', '-c', action='store_true', dest='compiler', 87 default=False, help='run compiler tests') 88 parser.add_argument( 89 '--tsc', action='store_true', dest='tsc', 90 default=False, help='run tsc tests') 91 parser.add_argument( 92 '--no-progress', action='store_false', dest='progress', default=True, 93 help='don\'t show progress bar') 94 parser.add_argument( 95 '--no-skip', action='store_false', dest='skip', default=True, 96 help='don\'t use skiplists') 97 parser.add_argument( 98 '--update', action='store_true', dest='update', default=False, 99 help='update skiplist') 100 parser.add_argument( 101 '--no-run-gc-in-place', action='store_true', dest='no_gip', default=False, 102 help='enable --run-gc-in-place mode') 103 parser.add_argument( 104 '--filter', '-f', action='store', dest='filter', 105 default="*", help='test filter regexp') 106 parser.add_argument( 107 '--es2panda-timeout', type=check_timeout, 108 dest='es2panda_timeout', default=60, help='es2panda translator timeout') 109 parser.add_argument( 110 '--paoc-timeout', type=check_timeout, 111 dest='paoc_timeout', default=600, help='paoc compiler timeout') 112 parser.add_argument( 113 '--timeout', type=check_timeout, 114 dest='timeout', default=10, help='JS runtime timeout') 115 parser.add_argument( 116 '--gc-type', dest='gc_type', default="g1-gc", help='Type of garbage collector') 117 parser.add_argument( 118 '--aot', action='store_true', dest='aot', default=False, 119 help='use AOT compilation') 120 parser.add_argument( 121 '--no-bco', action='store_false', dest='bco', default=True, 122 help='disable bytecodeopt') 123 parser.add_argument( 124 '--jit', action='store_true', dest='jit', default=False, 125 help='use JIT in interpreter') 126 parser.add_argument( 127 '--arm64-compiler-skip', action='store_true', dest='arm64_compiler_skip', default=False, 128 help='use skiplist for tests failing on aarch64 in AOT or JIT mode') 129 parser.add_argument( 130 '--arm64-qemu', action='store_true', dest='arm64_qemu', default=False, 131 help='launch all binaries in qemu aarch64') 132 parser.add_argument( 133 '--arm32-qemu', action='store_true', dest='arm32_qemu', default=False, 134 help='launch all binaries in qemu arm') 135 parser.add_argument( 136 '--test-list', dest='test_list', default=None, type=lambda arg: is_file(parser, arg), 137 help='run tests listed in file') 138 parser.add_argument( 139 '--aot-args', action='append', dest='aot_args', default=[], 140 help='Additional arguments that will passed to ark_aot') 141 parser.add_argument( 142 '--verbose', '-v', action='store_true', dest='verbose', default=False, 143 help='Enable verbose output') 144 parser.add_argument( 145 '--js-runtime', dest='js_runtime_path', default=None, type=lambda arg: is_directory(parser, arg), 146 help='the path of js vm runtime') 147 parser.add_argument( 148 '--LD_LIBRARY_PATH', dest='ld_library_path', default=None, help='LD_LIBRARY_PATH') 149 parser.add_argument( 150 '--tsc-path', dest='tsc_path', default=None, type=lambda arg: is_directory(parser, arg), 151 help='the path of tsc') 152 parser.add_argument('--hotfix', dest='hotfix', action='store_true', default=False, 153 help='run hotfix tests') 154 parser.add_argument('--hotreload', dest='hotreload', action='store_true', default=False, 155 help='run hotreload tests') 156 parser.add_argument('--coldfix', dest='coldfix', action='store_true', default=False, 157 help='run coldfix tests') 158 parser.add_argument('--coldreload', dest='coldreload', action='store_true', default=False, 159 help='run coldreload tests') 160 parser.add_argument('--base64', dest='base64', action='store_true', default=False, 161 help='run base64 tests') 162 parser.add_argument('--bytecode', dest='bytecode', action='store_true', default=False, 163 help='run bytecode tests') 164 parser.add_argument('--debugger', dest='debugger', action='store_true', default=False, 165 help='run debugger tests') 166 parser.add_argument('--debug', dest='debug', action='store_true', default=False, 167 help='run debug tests') 168 parser.add_argument('--enable-arkguard', action='store_true', dest='enable_arkguard', default=False, 169 help='enable arkguard for compiler tests') 170 parser.add_argument('--aop-transform', dest='aop_transform', action='store_true', default=False, 171 help='run debug tests') 172 173 return parser.parse_args() 174 175 176def run_subprocess_with_beta3(test_obj, cmd): 177 has_target_api = False 178 has_version_12 = False 179 has_sub_version = False 180 is_es2abc_cmd = False 181 182 for param in cmd: 183 if "es2abc" in param: 184 is_es2abc_cmd = True 185 if "--target-api-sub-version" in param: 186 has_sub_version = True 187 if "--target-api-version" in param: 188 has_target_api = True 189 if "12" in param: 190 has_version_12 = True 191 if is_es2abc_cmd and (not has_target_api or (has_version_12 and not has_sub_version)): 192 cmd.append("--target-api-sub-version=beta3") 193 if test_obj: 194 test_obj.log_cmd(cmd) 195 return subprocess.Popen( 196 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 197 198 199class Test: 200 def __init__(self, test_path, flags): 201 self.path = test_path 202 self.flags = flags 203 self.output = None 204 self.error = None 205 self.passed = None 206 self.skipped = None 207 self.reproduce = "" 208 209 def log_cmd(self, cmd): 210 self.reproduce += "\n" + ' '.join(cmd) 211 212 def get_path_to_expected(self): 213 if self.path.find(".d.ts") == -1: 214 return "%s-expected.txt" % (path.splitext(self.path)[0]) 215 return "%s-expected.txt" % (self.path[:self.path.find(".d.ts")]) 216 217 def run(self, runner): 218 test_abc_name = ("%s.abc" % (path.splitext(self.path)[0])).replace("/", "_") 219 test_abc_path = path.join(runner.build_dir, test_abc_name) 220 cmd = runner.cmd_prefix + [runner.es2panda] 221 cmd.extend(self.flags) 222 cmd.extend(["--output=" + test_abc_path]) 223 cmd.append(self.path) 224 process = run_subprocess_with_beta3(self, cmd) 225 out, err = process.communicate() 226 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 227 228 expected_path = self.get_path_to_expected() 229 try: 230 with open(expected_path, 'r') as fp: 231 expected = fp.read() 232 self.passed = expected == self.output and process.returncode in [ 233 0, 1] 234 except Exception: 235 self.passed = False 236 237 if not self.passed: 238 self.error = err.decode("utf-8", errors="ignore") 239 240 if os.path.exists(test_abc_path): 241 os.remove(test_abc_path) 242 243 return self 244 245 246class TSCTest(Test): 247 def __init__(self, test_path, flags): 248 Test.__init__(self, test_path, flags) 249 self.options = self.parse_options() 250 251 def parse_options(self): 252 test_options = {} 253 254 with open(self.path, "r", encoding="latin1") as f: 255 lines = f.read() 256 options = re.findall(r"//\s?@\w+:.*\n", lines) 257 258 for option in options: 259 separated = option.split(":") 260 opt = re.findall(r"\w+", separated[0])[0].lower() 261 value = separated[1].strip().lower() 262 263 if opt == "filename": 264 if opt in options: 265 test_options[opt].append(value) 266 else: 267 test_options[opt] = [value] 268 269 elif opt == "lib" or opt == "module": 270 test_options[opt] = [each.strip() 271 for each in value.split(",")] 272 elif value == "true" or value == "false": 273 test_options[opt] = value.lower() == "true" 274 else: 275 test_options[opt] = value 276 277 # TODO: Possibility of error: all exports will be catched, even the commented ones 278 if 'module' not in test_options and re.search(r"export ", lines): 279 test_options['module'] = [] 280 281 return test_options 282 283 def run(self, runner): 284 cmd = runner.cmd_prefix + [runner.es2panda, '--parse-only'] 285 cmd.extend(self.flags) 286 if "module" in self.options: 287 cmd.append('--module') 288 cmd.append(self.path) 289 process = run_subprocess_with_beta3(self, cmd) 290 out, err = process.communicate() 291 self.output = out.decode("utf-8", errors="ignore") 292 293 self.passed = True if process.returncode == 0 else False 294 295 if not self.passed: 296 self.error = err.decode("utf-8", errors="ignore") 297 298 return self 299 300 301class TestAop: 302 def __init__(self, cmd, compare_str, compare_abc_str, remove_file): 303 self.cmd = cmd 304 self.compare_str = compare_str 305 self.compare_abc_str = compare_abc_str 306 self.remove_file = remove_file 307 self.path = '' 308 self.output = None 309 self.error = None 310 self.passed = None 311 self.skipped = None 312 self.reproduce = "" 313 314 def log_cmd(self, cmd): 315 self.reproduce += ''.join(["\n", ' '.join(cmd)]) 316 317 def run(self, runner): 318 cmd = self.cmd 319 process = run_subprocess_with_beta3(self, cmd) 320 out, err = process.communicate() 321 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 322 323 if self.compare_str == '': 324 self.passed = True 325 else : 326 self.passed = self.output.startswith(self.compare_str) and process.returncode in [0, 1] 327 if self.remove_file != '' and os.path.exists(self.remove_file): 328 os.remove(self.remove_file) 329 330 if not self.passed: 331 self.error = err.decode("utf-8", errors="ignore") 332 333 abc_path = path.join(os.getcwd(), 'test_aop.abc') 334 if os.path.exists(abc_path): 335 if self.compare_abc_str != '': 336 with open(abc_path, "r") as abc_file: 337 self.passed = self.passed and abc_file.read() == self.compare_abc_str 338 os.remove(abc_path) 339 340 return self 341 342 343class Runner: 344 def __init__(self, args, name): 345 self.test_root = path.dirname(path.abspath(__file__)) 346 self.args = args 347 self.name = name 348 self.tests = [] 349 self.failed = 0 350 self.passed = 0 351 self.es2panda = path.join(args.build_dir, 'es2abc') 352 self.build_dir = args.build_dir 353 self.cmd_prefix = [] 354 self.ark_js_vm = "" 355 self.ark_aot_compiler = "" 356 self.ld_library_path = "" 357 358 if args.js_runtime_path: 359 self.ark_js_vm = path.join(args.js_runtime_path, 'ark_js_vm') 360 self.ark_aot_compiler = path.join(args.js_runtime_path, 'ark_aot_compiler') 361 362 if args.ld_library_path: 363 self.ld_library_path = args.ld_library_path 364 365 if args.arm64_qemu: 366 self.cmd_prefix = ["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu/"] 367 368 if args.arm32_qemu: 369 self.cmd_prefix = ["qemu-arm", "-L", "/usr/arm-linux-gnueabi"] 370 371 if not path.isfile(self.es2panda): 372 raise Exception("Cannot find es2panda binary: %s" % self.es2panda) 373 374 def add_directory(self, directory, extension, flags): 375 pass 376 377 def test_path(self, src): 378 pass 379 380 def run_test(self, test): 381 return test.run(self) 382 383 def run(self): 384 pool = multiprocessing.Pool() 385 result_iter = pool.imap_unordered( 386 self.run_test, self.tests, chunksize=32) 387 pool.close() 388 389 if self.args.progress: 390 from tqdm import tqdm 391 result_iter = tqdm(result_iter, total=len(self.tests)) 392 393 results = [] 394 for res in result_iter: 395 results.append(res) 396 397 self.tests = results 398 pool.join() 399 400 def deal_error(self, test): 401 path_str = test.path 402 err_col = {} 403 if test.error: 404 err_str = test.error.split('[')[0] if "patchfix" not in test.path else " patchfix throw error failed" 405 err_col = {"path" : [path_str], "status": ["fail"], "error" : [test.error], "type" : [err_str]} 406 else: 407 err_col = {"path" : [path_str], "status": ["fail"], "error" : ["Segmentation fault"], 408 "type" : ["Segmentation fault"]} 409 return err_col 410 411 def summarize(self): 412 print("") 413 fail_list = [] 414 success_list = [] 415 416 for test in self.tests: 417 assert(test.passed is not None) 418 if not test.passed: 419 fail_list.append(test) 420 else: 421 success_list.append(test) 422 423 if len(fail_list): 424 if self.args.error: 425 import pandas as pd 426 test_list = pd.DataFrame(columns=["path", "status", "error", "type"]) 427 for test in success_list: 428 suc_col = {"path" : [test.path], "status": ["success"], "error" : ["success"], "type" : ["success"]} 429 if self.args.error: 430 test_list = pd.concat([test_list, pd.DataFrame(suc_col)]) 431 print("Failed tests:") 432 for test in fail_list: 433 print(self.test_path(test.path)) 434 435 if self.args.error: 436 print("steps:", test.reproduce) 437 print("error:") 438 print(test.error) 439 print("\n") 440 err_col = self.deal_error(test) 441 test_list = pd.concat([test_list, pd.DataFrame(err_col)]) 442 443 if self.args.error: 444 test_list.to_csv('test_statistics.csv', index=False) 445 test_list["type"].value_counts().to_csv('type_statistics.csv', index_label="error") 446 print("Type statistics:\n", test_list["type"].value_counts()) 447 print("") 448 449 print("Summary(%s):" % self.name) 450 print("\033[37mTotal: %5d" % (len(self.tests))) 451 print("\033[92mPassed: %5d" % (len(self.tests) - len(fail_list))) 452 print("\033[91mFailed: %5d" % (len(fail_list))) 453 print("\033[0m") 454 455 return len(fail_list) 456 457 458class RegressionRunner(Runner): 459 def __init__(self, args): 460 Runner.__init__(self, args, "Regression") 461 462 def add_directory(self, directory, extension, flags, func=Test): 463 glob_expression = path.join( 464 self.test_root, directory, "*.%s" % (extension)) 465 files = glob(glob_expression) 466 files = fnmatch.filter(files, self.test_root + '**' + self.args.filter) 467 468 self.tests += list(map(lambda f: func(f, flags), files)) 469 470 def test_path(self, src): 471 return src 472 473 474class AbcToAsmRunner(Runner): 475 def __init__(self, args, is_debug): 476 Runner.__init__(self, args, "Abc2asm" if not is_debug else "Abc2asmDebug") 477 self.is_debug = is_debug 478 479 def add_directory(self, directory, extension, flags, func=Test): 480 glob_expression = path.join( 481 self.test_root, directory, "*.%s" % (extension)) 482 files = glob(glob_expression) 483 files = fnmatch.filter(files, self.test_root + '**' + self.args.filter) 484 485 self.tests += list(map(lambda f: AbcToAsmTest(f, flags, self.is_debug), files)) 486 487 def test_path(self, src): 488 return os.path.basename(src) 489 490 491class AbcToAsmTest(Test): 492 def __init__(self, test_path, flags, is_debug): 493 Test.__init__(self, test_path, flags) 494 self.is_debug = is_debug 495 496 def run(self, runner): 497 output_abc_file = ("%s.abc" % (path.splitext(self.path)[0])).replace("/", "_") 498 # source code compilation, generate an abc file 499 gen_abc_cmd = runner.cmd_prefix + [runner.es2panda] 500 if (self.is_debug): 501 gen_abc_cmd.extend(["--debug-info"]) 502 gen_abc_cmd.extend(["--module", "--dump-normalized-asm-program", "--output=" + output_abc_file]) 503 gen_abc_cmd.append(self.path) 504 process_gen_abc = run_subprocess_with_beta3(self, gen_abc_cmd) 505 gen_abc_out, gen_abc_err = process_gen_abc.communicate() 506 gen_abc_output = gen_abc_out.decode("utf-8", errors="ignore") 507 508 # If no abc file is generated, an error occurs during parser, but abc2asm function is normal. 509 if not os.path.exists(output_abc_file): 510 self.passed = True 511 return self 512 513 # abc file compilation 514 abc_to_asm_cmd = runner.cmd_prefix + [runner.es2panda] 515 if (self.is_debug): 516 abc_to_asm_cmd.extend(["--debug-info"]) 517 abc_to_asm_cmd.extend(["--module", "--dump-normalized-asm-program", "--enable-abc-input"]) 518 abc_to_asm_cmd.append(output_abc_file) 519 process_abc_to_asm = run_subprocess_with_beta3(self, abc_to_asm_cmd) 520 abc_to_asm_out, abc_to_asm_err = process_abc_to_asm.communicate() 521 abc_to_asm_output = abc_to_asm_out.decode("utf-8", errors="ignore") 522 523 self.passed = gen_abc_output == abc_to_asm_output and process_abc_to_asm.returncode in [0, 1] 524 if not self.passed: 525 self.error = "Comparison of dump results between source code compilation and abc file compilation failed." 526 if gen_abc_err: 527 self.error += "\n" + gen_abc_err.decode("utf-8", errors="ignore") 528 if abc_to_asm_err: 529 self.error += "\n" + abc_to_asm_err.decode("utf-8", errors="ignore") 530 531 os.remove(output_abc_file) 532 return self 533 534 535class TSCRunner(Runner): 536 def __init__(self, args): 537 Runner.__init__(self, args, "TSC") 538 539 if self.args.tsc_path: 540 self.tsc_path = self.args.tsc_path 541 else : 542 self.tsc_path = prepare_tsc_testcases(self.test_root) 543 544 self.add_directory("conformance", []) 545 self.add_directory("compiler", []) 546 547 def add_directory(self, directory, flags): 548 ts_suite_dir = path.join(self.tsc_path, 'tests/cases') 549 550 glob_expression = path.join( 551 ts_suite_dir, directory, "**/*.ts") 552 files = glob(glob_expression, recursive=True) 553 files = fnmatch.filter(files, ts_suite_dir + '**' + self.args.filter) 554 555 for f in files: 556 test_name = path.basename(f.split(".ts")[0]) 557 negative_references = path.join( 558 self.tsc_path, 'tests/baselines/reference') 559 is_negative = path.isfile(path.join(negative_references, 560 test_name + ".errors.txt")) 561 test = TSCTest(f, flags) 562 563 if 'target' in test.options: 564 targets = test.options['target'].replace(" ", "").split(',') 565 for target in targets: 566 if path.isfile(path.join(negative_references, 567 test_name + "(target=%s).errors.txt" % (target))): 568 is_negative = True 569 break 570 571 if is_negative or "filename" in test.options: 572 continue 573 574 with open(path.join(self.test_root, 'test_tsc_ignore_list.txt'), 'r') as failed_references: 575 if self.args.skip: 576 if path.relpath(f, self.tsc_path) in failed_references.read(): 577 continue 578 579 self.tests.append(test) 580 581 def test_path(self, src): 582 return src 583 584 585class CompilerRunner(Runner): 586 def __init__(self, args): 587 Runner.__init__(self, args, "Compiler") 588 589 def add_directory(self, directory, extension, flags): 590 if directory.endswith("projects"): 591 projects_path = path.join(self.test_root, directory) 592 for project in os.listdir(projects_path): 593 glob_expression = path.join(projects_path, project, "**/*.%s" % (extension)) 594 files = glob(glob_expression, recursive=True) 595 files = fnmatch.filter(files, self.test_root + '**' + self.args.filter) 596 self.tests.append(CompilerProjectTest(projects_path, project, files, flags)) 597 else: 598 glob_expression = path.join( 599 self.test_root, directory, "**/*.%s" % (extension)) 600 files = glob(glob_expression, recursive=True) 601 files = fnmatch.filter(files, self.test_root + '**' + self.args.filter) 602 self.tests += list(map(lambda f: CompilerTest(f, flags), files)) 603 604 def test_path(self, src): 605 return src 606 607 608class CompilerTest(Test): 609 def __init__(self, test_path, flags): 610 Test.__init__(self, test_path, flags) 611 612 def execute_arkguard(self, runner): 613 input_file_path = self.path 614 arkguard_root_dir = os.path.join(runner.test_root, "../../arkguard") 615 arkgurad_entry_path = os.path.join(arkguard_root_dir, "lib/cli/SecHarmony.js") 616 config_path = os.path.join(arkguard_root_dir, "test/compilerTestConfig.json") 617 arkguard_cmd = [ 618 'node', 619 '--no-warnings', 620 arkgurad_entry_path, 621 input_file_path, 622 '--config-path', 623 config_path, 624 '--inplace' 625 ] 626 self.log_cmd(arkguard_cmd) 627 process = subprocess.Popen(arkguard_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 628 out, err = process.communicate() 629 process.wait() 630 success = True 631 if err or process.returncode != 0: 632 success = False 633 self.passed = False 634 self.error = err.decode("utf-8", errors="ignore") 635 return success 636 637 def run(self, runner): 638 test_abc_name = ("%s.abc" % (path.splitext(self.path)[0])).replace("/", "_") 639 test_abc_path = path.join(runner.build_dir, test_abc_name) 640 es2abc_cmd = runner.cmd_prefix + [runner.es2panda] 641 es2abc_cmd.extend(self.flags) 642 es2abc_cmd.extend(["--output=" + test_abc_path]) 643 es2abc_cmd.append(self.path) 644 enable_arkguard = runner.args.enable_arkguard 645 if enable_arkguard: 646 success = self.execute_arkguard(runner) 647 if not success: 648 return self 649 650 process = run_subprocess_with_beta3(self, es2abc_cmd) 651 out, err = process.communicate() 652 if "--dump-assembly" in self.flags: 653 pa_expected_path = "".join([self.get_path_to_expected()[:self.get_path_to_expected().rfind(".txt")], 654 ".pa.txt"]) 655 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 656 try: 657 with open(pa_expected_path, 'r') as fp: 658 expected = fp.read() 659 self.passed = expected == self.output and process.returncode in [0, 1] 660 except Exception: 661 self.passed = False 662 if not self.passed: 663 self.error = err.decode("utf-8", errors="ignore") 664 if os.path.exists(test_abc_path): 665 os.remove(test_abc_path) 666 return self 667 if "--dump-debug-info" in self.flags: 668 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 669 try: 670 with open(self.get_path_to_expected(), 'r') as fp: 671 expected = fp.read() 672 self.passed = expected == self.output and process.returncode in [0, 1] 673 if os.path.exists(test_abc_path): 674 os.remove(test_abc_path) 675 return self 676 except Exception: 677 self.passed = False 678 if not self.passed: 679 self.error = err.decode("utf-8", errors="ignore") 680 if os.path.exists(test_abc_path): 681 os.remove(test_abc_path) 682 return self 683 if err: 684 self.passed = False 685 self.error = err.decode("utf-8", errors="ignore") 686 return self 687 688 ld_library_path = runner.ld_library_path 689 os.environ.setdefault("LD_LIBRARY_PATH", ld_library_path) 690 run_abc_cmd = [runner.ark_js_vm, '--enable-force-gc=false', test_abc_path] 691 self.log_cmd(run_abc_cmd) 692 693 process = subprocess.Popen(run_abc_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 694 out, err = process.communicate() 695 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 696 expected_path = self.get_path_to_expected() 697 try: 698 with open(expected_path, 'r') as fp: 699 expected = fp.read() 700 self.passed = expected == self.output and process.returncode in [0, 1] 701 except Exception: 702 self.passed = False 703 704 if not self.passed: 705 self.error = err.decode("utf-8", errors="ignore") 706 707 os.remove(test_abc_path) 708 709 return self 710 711 712class CompilerProjectTest(Test): 713 def __init__(self, projects_path, project, test_paths, flags): 714 Test.__init__(self, "", flags) 715 self.projects_path = projects_path 716 self.project = project 717 self.test_paths = test_paths 718 self.files_info_path = os.path.join(os.path.join(self.projects_path, self.project), 'filesInfo.txt') 719 # Skip execution if --dump-assembly exists in flags 720 self.requires_execution = "--dump-assembly" not in self.flags 721 self.file_record_mapping = None 722 self.generated_abc_inputs_path = os.path.join(os.path.join(self.projects_path, self.project), "abcinputs_gen") 723 self.abc_input_filenames = None 724 self.record_names_path = os.path.join(os.path.join(self.projects_path, self.project), 'recordnames.txt') 725 self.abc_inputs_path = os.path.join(os.path.join(self.projects_path, self.project), 'abcinputs') 726 self.deps_json_path = os.path.join(os.path.join(self.projects_path, self.project), 'deps-json.json') 727 728 def remove_project(self, runner): 729 project_path = runner.build_dir + "/" + self.project 730 if path.exists(project_path): 731 shutil.rmtree(project_path) 732 if path.exists(self.files_info_path): 733 os.remove(self.files_info_path) 734 if path.exists(self.generated_abc_inputs_path): 735 shutil.rmtree(self.generated_abc_inputs_path) 736 737 def get_file_absolute_path_and_name(self, runner): 738 sub_path = self.path[len(self.projects_path):] 739 file_relative_path = path.split(sub_path)[0] 740 file_name = path.split(sub_path)[1] 741 file_absolute_path = runner.build_dir + "/" + file_relative_path 742 return [file_absolute_path, file_name] 743 744 def gen_single_abc(self, runner): 745 for test_path in self.test_paths: 746 self.path = test_path 747 [file_absolute_path, file_name] = self.get_file_absolute_path_and_name(runner) 748 if not path.exists(file_absolute_path): 749 os.makedirs(file_absolute_path) 750 751 test_abc_name = ("%s.abc" % (path.splitext(file_name)[0])) 752 test_abc_path = path.join(file_absolute_path, test_abc_name) 753 es2abc_cmd = runner.cmd_prefix + [runner.es2panda] 754 es2abc_cmd.extend(self.flags) 755 es2abc_cmd.extend(['%s%s' % ("--output=", test_abc_path)]) 756 es2abc_cmd.append(self.path) 757 process = run_subprocess_with_beta3(self, es2abc_cmd) 758 out, err = process.communicate() 759 if err: 760 self.passed = False 761 self.error = err.decode("utf-8", errors="ignore") 762 self.remove_project(runner) 763 return self 764 765 def collect_record_mapping(self): 766 # Collect record mappings from recordnames.txt, file format: 767 # 'source_file_name:record_name\n' * n 768 if path.exists(self.record_names_path): 769 with open(self.record_names_path) as mapping_fp: 770 mapping_lines = mapping_fp.readlines() 771 self.file_record_mapping = {} 772 for mapping_line in mapping_lines: 773 cur_mapping = mapping_line[:-1].split(":") 774 self.file_record_mapping[cur_mapping[0]] = cur_mapping[1] 775 776 def get_record_name(self, test_path): 777 record_name = os.path.relpath(test_path, os.path.dirname(self.files_info_path)).split('.')[0] 778 if (self.file_record_mapping is not None and record_name in self.file_record_mapping): 779 record_name = self.file_record_mapping[record_name] 780 return record_name 781 782 def collect_abc_inputs(self, runner): 783 # Collect abc input information from the 'abcinputs' directory. Each txt file in the directory 784 # will generate a merged abc file with the same filename and serve as the final abc input. 785 # file format: 'source_file_name.ts\n' * n 786 if not path.exists(self.abc_inputs_path): 787 return 788 if not path.exists(self.generated_abc_inputs_path): 789 os.makedirs(self.generated_abc_inputs_path) 790 self.abc_input_filenames = {} 791 filenames = os.listdir(self.abc_inputs_path) 792 for filename in filenames: 793 if not filename.endswith('.txt'): 794 self.remove_project(runner) 795 raise Exception("Invalid abc input file: %s, only txt files are allowed in abcinputs directory: %s" 796 % (filename, self.abc_inputs_path)) 797 with open(path.join(self.abc_inputs_path, filename)) as abc_inputs_fp: 798 abc_inputs_lines = abc_inputs_fp.readlines() 799 for abc_input_line in abc_inputs_lines: 800 # filename is 'xxx.txt', remove '.txt' here 801 self.abc_input_filenames[abc_input_line[:-1]] = filename[:-len('.txt')] 802 803 def get_belonging_abc_input(self, test_path): 804 filename = os.path.relpath(test_path, os.path.dirname(self.files_info_path)) 805 if (self.abc_input_filenames is not None and filename in self.abc_input_filenames): 806 return self.abc_input_filenames[filename] 807 return None 808 809 def gen_abc_input_files_infos(self, runner, abc_files_infos, final_file_info_f): 810 for abc_files_info_name in abc_files_infos: 811 abc_files_info = abc_files_infos[abc_files_info_name] 812 if len(abc_files_info) != 0: 813 abc_input_path = path.join(self.generated_abc_inputs_path, abc_files_info_name) 814 abc_files_info_path = ("%s-filesInfo.txt" % (abc_input_path)) 815 abc_files_info_fd = os.open(abc_files_info_path, os.O_RDWR | os.O_CREAT | os.O_TRUNC) 816 abc_files_info_f = os.fdopen(abc_files_info_fd, 'w') 817 abc_files_info_f.writelines(abc_files_info) 818 final_file_info_f.writelines('%s-abcinput.abc;;;;%s;\n' % (abc_input_path, abc_files_info_name)) 819 820 def gen_files_info(self, runner): 821 # After collect_record_mapping, self.file_record_mapping stores {'source file name' : 'source file record name'} 822 self.collect_record_mapping() 823 # After collect_abc_inputs, self.abc_input_filenames stores {'source file name' : 'belonging abc input name'} 824 self.collect_abc_inputs(runner) 825 826 fd = os.open(self.files_info_path, os.O_RDWR | os.O_CREAT | os.O_TRUNC) 827 f = os.fdopen(fd, 'w') 828 abc_files_infos = {} 829 for test_path in self.test_paths: 830 record_name = self.get_record_name(test_path) 831 module_kind = 'esm' 832 if (os.path.basename(test_path).startswith("commonjs")): 833 module_kind = 'commonjs' 834 is_shared_module = 'false' 835 if (os.path.basename(test_path).startswith("sharedmodule")): 836 is_shared_module = 'true' 837 file_info = ('%s;%s;%s;%s;%s;%s\n' % (test_path, record_name, module_kind, 838 os.path.relpath(test_path, self.projects_path), record_name, 839 is_shared_module)) 840 belonging_abc_input = self.get_belonging_abc_input(test_path) 841 if belonging_abc_input is not None: 842 if not belonging_abc_input in abc_files_infos: 843 abc_files_infos[belonging_abc_input] = [] 844 abc_files_infos[belonging_abc_input].append(file_info) 845 else: 846 f.writelines(file_info) 847 if (os.path.exists(self.deps_json_path)): 848 record_name = self.get_record_name(self.deps_json_path) 849 file_info = ('%s;%s;%s;%s;%s;%s\n' % (self.deps_json_path, record_name, 'esm', 850 os.path.relpath(self.deps_json_path, self.projects_path), record_name, 851 'false')) 852 self.gen_abc_input_files_infos(runner, abc_files_infos, f) 853 f.close() 854 855 def gen_es2abc_cmd(self, runner, input_file, output_file): 856 es2abc_cmd = runner.cmd_prefix + [runner.es2panda] 857 858 new_flags = self.flags 859 if "--cache-file" in new_flags and len(self.test_paths) == 1: 860 # Generate cache-file test case in single thread 861 new_flags.remove("--cache-file") 862 protobin_path = f"{self.test_paths[0].rsplit('.', 1)[0]}.protobin" 863 self.protoBin_file_path = protobin_path 864 es2abc_cmd.append('--cache-file=%s' % (protobin_path)) 865 866 es2abc_cmd.extend(new_flags) 867 es2abc_cmd.extend(['%s%s' % ("--output=", output_file)]) 868 es2abc_cmd.append(input_file) 869 return es2abc_cmd 870 871 def gen_merged_abc_for_abc_input(self, runner, files_info_name): 872 self.passed = True 873 if not files_info_name.endswith(".txt"): 874 return 875 abc_input_files_info_path = path.join(self.generated_abc_inputs_path, files_info_name) 876 abc_input_merged_abc_path = path.join(self.generated_abc_inputs_path, 877 '%s-abcinput.abc' % (files_info_name[:-len('-filesInfo.txt')])) 878 879 abc_input_file_path = '@' + abc_input_files_info_path 880 if "unmerged_abc_input" in self.generated_abc_inputs_path: 881 self.flags.remove("--merge-abc") 882 with open(abc_input_files_info_path, 'r') as fp: 883 abc_input_file_path = fp.read().split(';')[0] 884 885 es2abc_cmd = self.gen_es2abc_cmd(runner, abc_input_file_path, abc_input_merged_abc_path) 886 process = run_subprocess_with_beta3(self, es2abc_cmd) 887 out, err = process.communicate() 888 if err: 889 self.passed = False 890 self.error = err.decode("utf-8", errors="ignore") 891 892 def gen_merged_abc(self, runner): 893 # Generate abc inputs 894 if (os.path.exists(self.generated_abc_inputs_path)): 895 files_info_names = os.listdir(self.generated_abc_inputs_path) 896 for filename in files_info_names: 897 self.gen_merged_abc_for_abc_input(runner, filename) 898 if (not self.passed): 899 self.remove_project(runner) 900 return self 901 # Generate the abc to be tested 902 for test_path in self.test_paths: 903 self.path = test_path 904 if (self.path.endswith("-exec.ts")) or (self.path.endswith("-exec.js")): 905 exec_file_path = self.path 906 [file_absolute_path, file_name] = self.get_file_absolute_path_and_name(runner) 907 if not path.exists(file_absolute_path): 908 os.makedirs(file_absolute_path) 909 test_abc_name = ("%s.abc" % (path.splitext(file_name)[0])) 910 output_abc_name = path.join(file_absolute_path, test_abc_name) 911 912 # reverse merge-abc flag 913 if "merge_abc_consistence_check" in self.path: 914 if "--merge-abc" in self.flags: 915 self.flags.remove("--merge-abc") 916 else: 917 self.flags.append("--merge-abc") 918 919 es2abc_cmd = self.gen_es2abc_cmd(runner, '@' + self.files_info_path, output_abc_name) 920 compile_context_info_path = path.join(path.join(self.projects_path, self.project), "compileContextInfo.json") 921 if path.exists(compile_context_info_path): 922 es2abc_cmd.append("%s%s" % ("--compile-context-info=", compile_context_info_path)) 923 process = run_subprocess_with_beta3(self, es2abc_cmd) 924 self.path = exec_file_path 925 out, err = [None, None] 926 927 # Check single-thread execution timeout when required 928 if "--file-threads=0" in self.flags: 929 try: 930 out, err = process.communicate(timeout=60) 931 except: 932 process.kill() 933 print("Generating the abc file timed out.") 934 else: 935 out, err = process.communicate() 936 937 # restore merge-abc flag 938 if "merge_abc_consistence_check" in self.path and "--merge-abc" not in self.flags: 939 self.flags.append("--merge-abc") 940 941 # Check dump-assembly outputs when required 942 if "--dump-assembly" in self.flags: 943 pa_expected_path = "".join([self.get_path_to_expected()[:self.get_path_to_expected().rfind(".txt")], 944 ".pa.txt"]) 945 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 946 if "merge_abc_consistence_check" in self.path: 947 self.output = self.output.split('.')[0] 948 try: 949 with open(pa_expected_path, 'r') as fp: 950 expected = fp.read() 951 self.passed = expected == self.output and process.returncode in [0, 1] 952 except Exception: 953 self.passed = False 954 if not self.passed: 955 self.error = err.decode("utf-8", errors="ignore") 956 self.remove_project(runner) 957 return self 958 else: 959 return self 960 961 if err: 962 self.passed = False 963 self.error = err.decode("utf-8", errors="ignore") 964 self.remove_project(runner) 965 return self 966 967 def run(self, runner): 968 # Compile all ts source files in the project to abc files. 969 if ("--merge-abc" in self.flags): 970 self.gen_files_info(runner) 971 self.gen_merged_abc(runner) 972 else: 973 self.gen_single_abc(runner) 974 975 if (not self.requires_execution): 976 self.remove_project(runner) 977 return self 978 979 # Run test files that need to be executed in the project. 980 for test_path in self.test_paths: 981 self.path = test_path 982 if self.path.endswith("-exec.ts"): 983 [file_absolute_path, file_name] = self.get_file_absolute_path_and_name(runner) 984 985 entry_point_name = path.splitext(file_name)[0] 986 test_abc_name = ("%s.abc" % entry_point_name) 987 test_abc_path = path.join(file_absolute_path, test_abc_name) 988 989 ld_library_path = runner.ld_library_path 990 os.environ.setdefault("LD_LIBRARY_PATH", ld_library_path) 991 run_abc_cmd = [runner.ark_js_vm] 992 if ("--merge-abc" in self.flags): 993 run_abc_cmd.extend(["--entry-point", entry_point_name]) 994 run_abc_cmd.extend([test_abc_path]) 995 self.log_cmd(run_abc_cmd) 996 997 process = subprocess.Popen(run_abc_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 998 out, err = process.communicate() 999 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 1000 expected_path = self.get_path_to_expected() 1001 try: 1002 with open(expected_path, 'r') as fp: 1003 expected = fp.read() 1004 self.passed = expected == self.output and process.returncode in [0, 1] 1005 except Exception: 1006 self.passed = False 1007 1008 if not self.passed: 1009 self.error = err.decode("utf-8", errors="ignore") 1010 self.remove_project(runner) 1011 return self 1012 1013 self.passed = True 1014 1015 self.remove_project(runner) 1016 return self 1017 1018 1019class TSDeclarationTest(Test): 1020 def get_path_to_expected(self): 1021 file_name = self.path[:self.path.find(".d.ts")] 1022 return "%s-expected.txt" % file_name 1023 1024 1025class BcVersionRunner(Runner): 1026 def __init__(self, args): 1027 Runner.__init__(self, args, "Target bc version") 1028 self.ts2abc = path.join(self.test_root, '..', 'scripts', 'ts2abc.js') 1029 1030 def add_cmd(self): 1031 api_sub_version_list = ["beta1", "beta2", "beta3"] 1032 for api_version in range(8, 14): 1033 cmd = self.cmd_prefix + [self.es2panda] 1034 cmd += ["--target-bc-version"] 1035 cmd += ["--target-api-version"] 1036 cmd += [str(api_version)] 1037 self.tests += [BcVersionTest(cmd, api_version)] 1038 node_cmd = ["node"] + [self.ts2abc] 1039 node_cmd += ["".join(["es2abc=", self.es2panda])] 1040 node_cmd += ["--target-api-version"] 1041 node_cmd += [str(api_version)] 1042 self.tests += [BcVersionTest(node_cmd, api_version)] 1043 1044 # Add tests for "--target-api-sub-version" option 1045 if api_version == 12: 1046 for api_sub_version in api_sub_version_list: 1047 new_cmd = cmd.copy() 1048 new_cmd += ["--target-api-sub-version", api_sub_version] 1049 self.tests += [BcVersionTest(new_cmd, str(api_version) + '_' + api_sub_version)] 1050 new_node_cmd = node_cmd.copy() 1051 new_node_cmd += ["--target-api-sub-version", api_sub_version] 1052 self.tests += [BcVersionTest(new_node_cmd, str(api_version) + '_' + api_sub_version)] 1053 1054 def run(self): 1055 for test in self.tests: 1056 test.run() 1057 1058 1059class BcVersionTest(Test): 1060 def __init__(self, cmd, api_version): 1061 Test.__init__(self, "", 0) 1062 self.cmd = cmd 1063 self.api_version = api_version 1064 self.bc_version_expect = { 1065 8: "12.0.6.0", 1066 9: "9.0.0.0", 1067 10: "9.0.0.0", 1068 11: "11.0.2.0", 1069 12: "12.0.2.0", 1070 "12_beta1": "12.0.2.0", 1071 "12_beta2": "12.0.2.0", 1072 "12_beta3": "12.0.6.0", 1073 13: "12.0.6.0" 1074 } 1075 self.es2abc_script_expect = { 1076 8: "0.0.0.2", 1077 9: "9.0.0.0", 1078 10: "9.0.0.0", 1079 11: "11.0.2.0", 1080 12: "12.0.2.0", 1081 "12_beta1": "12.0.2.0", 1082 "12_beta2": "12.0.2.0", 1083 "12_beta3": "12.0.6.0", 1084 13: "12.0.6.0" 1085 } 1086 1087 def run(self): 1088 process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 1089 out, err = process.communicate() 1090 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 1091 if self.cmd[0] == "node": 1092 self.passed = self.es2abc_script_expect.get(self.api_version) == self.output and process.returncode in [0, 1] 1093 else: 1094 self.passed = self.bc_version_expect.get(self.api_version) == self.output and process.returncode in [0, 1] 1095 if not self.passed: 1096 self.error = err.decode("utf-8", errors="ignore") 1097 return self 1098 1099 1100class TransformerRunner(Runner): 1101 def __init__(self, args): 1102 Runner.__init__(self, args, "Transformer") 1103 1104 def add_directory(self, directory, extension, flags): 1105 glob_expression = path.join( 1106 self.test_root, directory, "**/*.%s" % (extension)) 1107 files = glob(glob_expression, recursive=True) 1108 files = fnmatch.filter(files, self.test_root + '**' + self.args.filter) 1109 1110 self.tests += list(map(lambda f: TransformerTest(f, flags), files)) 1111 1112 def test_path(self, src): 1113 return src 1114 1115 1116class TransformerInTargetApiVersion10Runner(Runner): 1117 def __init__(self, args): 1118 Runner.__init__(self, args, "TransformerInTargetApiVersion10") 1119 1120 def add_directory(self, directory, extension, flags): 1121 glob_expression = path.join( 1122 self.test_root, directory, "**/*.%s" % (extension)) 1123 files = glob(glob_expression, recursive=True) 1124 files = fnmatch.filter(files, self.test_root + '**' + self.args.filter) 1125 1126 self.tests += list(map(lambda f: TransformerTest(f, flags), files)) 1127 1128 def test_path(self, src): 1129 return src 1130 1131 1132class TransformerTest(Test): 1133 def __init__(self, test_path, flags): 1134 Test.__init__(self, test_path, flags) 1135 1136 def get_path_to_expected(self): 1137 return "%s-transformed-expected.txt" % (path.splitext(self.path)[0]) 1138 1139 def run(self, runner): 1140 cmd = runner.cmd_prefix + [runner.es2panda] 1141 cmd.extend(self.flags) 1142 cmd.append(self.path) 1143 process = run_subprocess_with_beta3(self, cmd) 1144 out, err = process.communicate() 1145 self.output = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 1146 1147 expected_path = self.get_path_to_expected() 1148 try: 1149 with open(expected_path, 'r') as fp: 1150 expected = fp.read() 1151 self.passed = expected == self.output and process.returncode in [0, 1] 1152 except Exception: 1153 self.passed = False 1154 1155 if not self.passed: 1156 self.error = err.decode("utf-8", errors="ignore") 1157 1158 return self 1159 1160 1161class PatchTest(Test): 1162 def __init__(self, test_path, mode_arg, target_version, preserve_files): 1163 Test.__init__(self, test_path, "") 1164 self.mode = mode_arg 1165 self.target_version = target_version 1166 self.preserve_files = preserve_files 1167 1168 def gen_cmd(self, runner): 1169 symbol_table_file = os.path.join(self.path, 'base.map') 1170 origin_input_file = 'base.js' 1171 origin_output_abc = os.path.join(self.path, 'base.abc') 1172 modified_input_file = 'base_mod.js' 1173 modified_output_abc = os.path.join(self.path, 'patch.abc') 1174 target_version_cmd = "" 1175 if self.target_version > 0: 1176 target_version_cmd = "--target-api-version=" + str(self.target_version) 1177 1178 gen_base_cmd = runner.cmd_prefix + [runner.es2panda, '--module', target_version_cmd] 1179 if 'record-name-with-dots' in os.path.basename(self.path): 1180 gen_base_cmd.extend(['--merge-abc', '--record-name=record.name.with.dots']) 1181 gen_base_cmd.extend(['--dump-symbol-table', symbol_table_file]) 1182 gen_base_cmd.extend(['--output', origin_output_abc]) 1183 gen_base_cmd.extend([os.path.join(self.path, origin_input_file)]) 1184 self.log_cmd(gen_base_cmd) 1185 1186 if self.mode == 'hotfix': 1187 mode_arg = ["--generate-patch"] 1188 elif self.mode == 'hotreload': 1189 mode_arg = ["--hot-reload"] 1190 elif self.mode == 'coldfix': 1191 mode_arg = ["--generate-patch", "--cold-fix"] 1192 elif self.mode == 'coldreload': 1193 mode_arg = ["--cold-reload"] 1194 1195 patch_test_cmd = runner.cmd_prefix + [runner.es2panda, '--module', target_version_cmd] 1196 patch_test_cmd.extend(mode_arg) 1197 patch_test_cmd.extend(['--input-symbol-table', symbol_table_file]) 1198 patch_test_cmd.extend(['--output', modified_output_abc]) 1199 patch_test_cmd.extend([os.path.join(self.path, modified_input_file)]) 1200 if 'record-name-with-dots' in os.path.basename(self.path): 1201 patch_test_cmd.extend(['--merge-abc', '--record-name=record.name.with.dots']) 1202 dump_assembly_testname = [ 1203 'modify-anon-content-keep-origin-name', 1204 'modify-class-memeber-function', 1205 'exist-lexenv-3', 1206 'lexenv-reduce', 1207 'lexenv-increase'] 1208 for name in dump_assembly_testname: 1209 if name in os.path.basename(self.path): 1210 patch_test_cmd.extend(['--dump-assembly']) 1211 self.log_cmd(patch_test_cmd) 1212 1213 return gen_base_cmd, patch_test_cmd, symbol_table_file, origin_output_abc, modified_output_abc 1214 1215 def run(self, runner): 1216 gen_base_cmd, patch_test_cmd, symbol_table_file, origin_output_abc, modified_output_abc = self.gen_cmd(runner) 1217 1218 process_base = run_subprocess_with_beta3(None, gen_base_cmd) 1219 stdout_base, stderr_base = process_base.communicate(timeout=runner.args.es2panda_timeout) 1220 if stderr_base: 1221 self.passed = False 1222 self.error = stderr_base.decode("utf-8", errors="ignore") 1223 self.output = stdout_base.decode("utf-8", errors="ignore") + stderr_base.decode("utf-8", errors="ignore") 1224 else: 1225 process_patch = run_subprocess_with_beta3(None, patch_test_cmd) 1226 process_patch = subprocess.Popen(patch_test_cmd, stdout=subprocess.PIPE, 1227 stderr=subprocess.PIPE) 1228 stdout_patch, stderr_patch = process_patch.communicate(timeout=runner.args.es2panda_timeout) 1229 if stderr_patch: 1230 self.passed = False 1231 self.error = stderr_patch.decode("utf-8", errors="ignore") 1232 self.output = stdout_patch.decode("utf-8", errors="ignore") + stderr_patch.decode("utf-8", errors="ignore") 1233 1234 expected_path = os.path.join(self.path, 'expected.txt') 1235 try: 1236 with open(expected_path, 'r') as fp: 1237 # ignore license description lines and skip leading blank lines 1238 expected = (''.join((fp.readlines()[12:]))).lstrip() 1239 self.passed = expected == self.output 1240 except Exception: 1241 self.passed = False 1242 1243 if not self.passed: 1244 self.error = "expected output:" + os.linesep + expected + os.linesep + "actual output:" + os.linesep +\ 1245 self.output 1246 if not self.preserve_files: 1247 os.remove(symbol_table_file) 1248 os.remove(origin_output_abc) 1249 if (os.path.exists(modified_output_abc)): 1250 os.remove(modified_output_abc) 1251 return self 1252 1253 1254class PatchRunner(Runner): 1255 def __init__(self, args, name): 1256 Runner.__init__(self, args, name) 1257 self.preserve_files = args.error 1258 self.tests_in_dirs = [] 1259 dirs = os.listdir(path.join(self.test_root, "patch")) 1260 for target_version_path in dirs: 1261 self.add_tests(target_version_path, name) 1262 1263 def add_tests(self, target_version_path, name): 1264 name_dir = os.path.join(self.test_root, "patch", target_version_path, name) 1265 if not os.path.exists(name_dir): 1266 return 1267 target_version = 0 1268 if target_version_path.isdigit(): 1269 target_version = int(target_version_path) 1270 for sub_path in os.listdir(name_dir): 1271 test_base_path = os.path.join(name_dir, sub_path) 1272 if name != "coldreload": 1273 for test_dir in os.listdir(test_base_path): 1274 test_path = os.path.join(test_base_path, test_dir) 1275 self.tests_in_dirs.append(test_path) 1276 self.tests.append(PatchTest(test_path, name, target_version, self.preserve_files)) 1277 else: 1278 self.tests_in_dirs.append(test_base_path) 1279 self.tests.append(PatchTest(test_base_path, name, target_version, self.preserve_files)) 1280 1281 def test_path(self, src): 1282 return os.path.basename(src) 1283 1284 1285class HotfixRunner(PatchRunner): 1286 def __init__(self, args): 1287 PatchRunner.__init__(self, args, "hotfix") 1288 1289 1290class HotreloadRunner(PatchRunner): 1291 def __init__(self, args): 1292 PatchRunner.__init__(self, args, "hotreload") 1293 1294 1295class ColdfixRunner(PatchRunner): 1296 def __init__(self, args): 1297 PatchRunner.__init__(self, args, "coldfix") 1298 1299 1300class ColdreloadRunner(PatchRunner): 1301 def __init__(self, args): 1302 PatchRunner.__init__(self, args, "coldreload") 1303 1304 1305class DebuggerTest(Test): 1306 def __init__(self, test_path, mode): 1307 Test.__init__(self, test_path, "") 1308 self.mode = mode 1309 1310 def run(self, runner): 1311 cmd = runner.cmd_prefix + [runner.es2panda, "--module"] 1312 input_file_name = 'base.js' 1313 if self.mode == "debug-mode": 1314 cmd.extend(['--debug-info']) 1315 cmd.extend([os.path.join(self.path, input_file_name)]) 1316 cmd.extend(['--dump-assembly']) 1317 process = run_subprocess_with_beta3(self, cmd) 1318 stdout, stderr = process.communicate(timeout=runner.args.es2panda_timeout) 1319 if stderr: 1320 self.passed = False 1321 self.error = stderr.decode("utf-8", errors="ignore") 1322 return self 1323 1324 self.output = stdout.decode("utf-8", errors="ignore") 1325 1326 expected_path = os.path.join(self.path, 'expected.txt') 1327 try: 1328 with open(expected_path, 'r') as fp: 1329 expected = (''.join((fp.readlines()[12:]))).lstrip() 1330 self.passed = expected == self.output 1331 except Exception: 1332 self.passed = False 1333 1334 if not self.passed: 1335 self.error = "expected output:" + os.linesep + expected + os.linesep + "actual output:" + os.linesep +\ 1336 self.output 1337 1338 if os.path.exists("base.abc"): 1339 os.remove("base.abc") 1340 1341 return self 1342 1343 1344class DebuggerRunner(Runner): 1345 def __init__(self, args): 1346 Runner.__init__(self, args, "debugger") 1347 self.test_directory = path.join(self.test_root, "debugger") 1348 self.add_test() 1349 1350 def add_test(self): 1351 self.tests = [] 1352 self.tests.append(DebuggerTest(os.path.join(self.test_directory, "debugger-in-debug"), "debug-mode")) 1353 self.tests.append(DebuggerTest(os.path.join(self.test_directory, "debugger-in-release"), "release-mode")) 1354 1355 1356class Base64Test(Test): 1357 def __init__(self, test_path, input_type): 1358 Test.__init__(self, test_path, "") 1359 self.input_type = input_type 1360 1361 def run(self, runner): 1362 cmd = runner.cmd_prefix + [runner.es2panda, "--base64Output"] 1363 if self.input_type == "file": 1364 input_file_name = 'input.js' 1365 cmd.extend(['--source-file', input_file_name]) 1366 cmd.extend([os.path.join(self.path, input_file_name)]) 1367 elif self.input_type == "string": 1368 input_file = os.path.join(self.path, "input.txt") 1369 try: 1370 with open(input_file, 'r') as fp: 1371 base64_input = (''.join((fp.readlines()[12:]))).lstrip() # ignore license description lines 1372 cmd.extend(["--base64Input", base64_input]) 1373 except Exception: 1374 self.passed = False 1375 elif self.input_type == "targetApiVersion": 1376 # base64 test for all available target api version. 1377 version = os.path.basename(self.path) 1378 cmd.extend(['--target-api-version', version]) 1379 if version == "12": 1380 cmd.append("--target-api-sub-version=beta3") 1381 input_file = os.path.join(self.path, "input.txt") 1382 try: 1383 with open(input_file, 'r') as fp: 1384 base64_input = (''.join((fp.readlines()[12:]))).lstrip() # ignore license description lines 1385 cmd.extend(["--base64Input", base64_input]) 1386 except Exception: 1387 self.passed = False 1388 else: 1389 self.error = "Unsupported base64 input type" 1390 self.passed = False 1391 return self 1392 1393 version = os.path.basename(self.path) 1394 if not self.input_type == "targetApiVersion": 1395 cmd.append("--target-api-sub-version=beta3") 1396 1397 self.log_cmd(cmd) 1398 1399 process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 1400 stdout, stderr = process.communicate(timeout=runner.args.es2panda_timeout) 1401 if stderr: 1402 self.passed = False 1403 self.error = stderr.decode("utf-8", errors="ignore") 1404 return self 1405 1406 self.output = stdout.decode("utf-8", errors="ignore") 1407 1408 expected_path = os.path.join(self.path, 'expected.txt') 1409 try: 1410 with open(expected_path, 'r') as fp: 1411 expected = (''.join((fp.readlines()[12:]))).lstrip() 1412 self.passed = expected == self.output 1413 except Exception: 1414 self.passed = False 1415 1416 if not self.passed: 1417 self.error = "expected output:" + os.linesep + expected + os.linesep + "actual output:" + os.linesep +\ 1418 self.output 1419 1420 return self 1421 1422 1423class Base64Runner(Runner): 1424 def __init__(self, args): 1425 Runner.__init__(self, args, "Base64") 1426 self.test_directory = path.join(self.test_root, "base64") 1427 self.add_test() 1428 1429 def add_test(self): 1430 self.tests = [] 1431 self.tests.append(Base64Test(os.path.join(self.test_directory, "inputFile"), "file")) 1432 self.tests.append(Base64Test(os.path.join(self.test_directory, "inputString"), "string")) 1433 # current target api version is 12, once a new version is addded, a new testcase should be added here. 1434 current_version = 12 1435 available_target_api_versions = [9, 10, 11, current_version] 1436 for version in available_target_api_versions: 1437 self.tests.append(Base64Test(os.path.join(self.test_directory, "availableTargetApiVersion", str(version)), 1438 "targetApiVersion")) 1439 1440 def test_path(self, src): 1441 return os.path.basename(src) 1442 1443 1444class BytecodeRunner(Runner): 1445 def __init__(self, args): 1446 Runner.__init__(self, args, "Bytecode") 1447 1448 def add_directory(self, directory, extension, flags, func=Test): 1449 glob_expression = path.join( 1450 self.test_root, directory, "**/*.%s" % (extension)) 1451 files = glob(glob_expression, recursive=True) 1452 files = fnmatch.filter(files, self.test_root + '**' + self.args.filter) 1453 self.tests += list(map(lambda f: func(f, flags), files)) 1454 1455 def test_path(self, src): 1456 return src 1457 1458 1459class CompilerTestInfo(object): 1460 def __init__(self, directory, extension, flags): 1461 self.directory = directory 1462 self.extension = extension 1463 self.flags = flags 1464 1465 def update_dir(self, prefiex_dir): 1466 self.directory = os.path.sep.join([prefiex_dir, self.directory]) 1467 1468 1469# Copy compiler directory to test/.local directory, and do inplace obfuscation. 1470def prepare_for_obfuscation(compiler_test_infos, test_root): 1471 tmp_dir_name = ".local" 1472 tmp_path = os.path.join(test_root, tmp_dir_name) 1473 if not os.path.exists(tmp_path): 1474 os.mkdir(tmp_path) 1475 1476 test_root_dirs = set() 1477 for info in compiler_test_infos: 1478 root_dir = info.directory.split("/")[0] 1479 test_root_dirs.add(root_dir) 1480 1481 for test_dir in test_root_dirs: 1482 src_dir = os.path.join(test_root, test_dir) 1483 target_dir = os.path.join(tmp_path, test_dir) 1484 if os.path.exists(target_dir): 1485 shutil.rmtree(target_dir) 1486 shutil.copytree(src_dir, target_dir) 1487 1488 for info in compiler_test_infos: 1489 info.update_dir(tmp_dir_name) 1490 1491 1492def add_directory_for_regression(runners, args): 1493 runner = RegressionRunner(args) 1494 runner.add_directory("parser/concurrent", "js", ["--module", "--dump-ast"]) 1495 runner.add_directory("parser/js", "js", ["--parse-only", "--dump-ast"]) 1496 runner.add_directory("parser/script", "ts", ["--parse-only", "--dump-ast"]) 1497 runner.add_directory("parser/ts", "ts", 1498 ["--parse-only", "--module", "--dump-ast"]) 1499 runner.add_directory("parser/ts/type_checker", "ts", 1500 ["--parse-only", "--enable-type-check", "--module", "--dump-ast"]) 1501 runner.add_directory("parser/ts/cases/declaration", "d.ts", 1502 ["--parse-only", "--module", "--dump-ast"], TSDeclarationTest) 1503 runner.add_directory("parser/commonjs", "js", ["--commonjs", "--parse-only", "--dump-ast"]) 1504 runner.add_directory("parser/binder", "js", ["--dump-assembly", "--dump-literal-buffer", "--module", "--target-api-sub-version=beta3"]) 1505 runner.add_directory("parser/binder", "ts", ["--dump-assembly", "--dump-literal-buffer", "--module", "--target-api-sub-version=beta3"]) 1506 runner.add_directory("parser/binder/noModule", "ts", ["--dump-assembly", "--dump-literal-buffer", "--target-api-sub-version=beta3"]) 1507 runner.add_directory("parser/binder/api12beta2", "js", ["--dump-assembly", "--target-api-version=12", "--target-api-sub-version=beta2"]) 1508 runner.add_directory("parser/binder/debugInfo", "ts", ["--dump-assembly", "--dump-literal-buffer", "--debug-info", "--module"]) 1509 runner.add_directory("parser/js/emptySource", "js", ["--dump-assembly"]) 1510 runner.add_directory("parser/js/language/arguments-object", "js", ["--parse-only"]) 1511 runner.add_directory("parser/js/language/statements/for-statement", "js", ["--parse-only", "--dump-ast"]) 1512 runner.add_directory("parser/js/language/expressions/optional-chain", "js", ["--parse-only", "--dump-ast"]) 1513 runner.add_directory("parser/js/language/import/syntax", "js", 1514 ["--parse-only", "--module", "--target-api-sub-version=beta3"]) 1515 runner.add_directory("parser/js/language/import/syntax/beta2", "js", 1516 ["--parse-only", "--module", "--target-api-version=12", "--target-api-sub-version=beta2"]) 1517 runner.add_directory("parser/js/language/import", "ts", 1518 ["--dump-assembly", "--dump-literal-buffer", "--module", "--target-api-sub-version=beta3"]) 1519 runner.add_directory("parser/sendable_class", "ts", 1520 ["--dump-assembly", "--dump-literal-buffer", "--module", "--target-api-sub-version=beta3"]) 1521 runner.add_directory("parser/sendable_class/api12beta2", "ts", 1522 ["--dump-assembly", "--dump-literal-buffer", "--module", "--target-api-version=12", "--target-api-sub-version=beta2"]) 1523 runner.add_directory("parser/unicode", "js", ["--parse-only"]) 1524 runner.add_directory("parser/ts/stack_overflow", "ts", ["--parse-only", "--dump-ast"]) 1525 runner.add_directory("parser/js/module-record/module-record-field-name-option.js", "js", 1526 ["--module-record-field-name=abc", "--source-file=abc", "--module", "--dump-normalized-asm-program"]) 1527 1528 runners.append(runner) 1529 1530 transformer_runner = TransformerRunner(args) 1531 transformer_runner.add_directory("parser/ts/transformed_cases", "ts", 1532 ["--parse-only", "--module", "--dump-transformed-ast", 1533 "--check-transformed-ast-structure"]) 1534 1535 runners.append(transformer_runner) 1536 1537 bc_version_runner = BcVersionRunner(args) 1538 bc_version_runner.add_cmd() 1539 1540 runners.append(bc_version_runner) 1541 1542 transformer_api_version_10_runner = TransformerInTargetApiVersion10Runner(args) 1543 transformer_api_version_10_runner.add_directory("parser/ts/transformed_cases_api_version_10", "ts", 1544 ["--parse-only", "--module", "--target-api-version=10", 1545 "--dump-transformed-ast"]) 1546 1547 runners.append(transformer_api_version_10_runner) 1548 1549def add_directory_for_asm(runners, args, mode = ""): 1550 runner = AbcToAsmRunner(args, True if mode == "debug" else False) 1551 runner.add_directory("abc2asm/js", "js", []) 1552 runner.add_directory("abc2asm/ts", "ts", []) 1553 runner.add_directory("compiler/js", "js", []) 1554 runner.add_directory("compiler/ts/cases/compiler", "ts", []) 1555 runner.add_directory("compiler/ts/projects", "ts", ["--module"]) 1556 runner.add_directory("compiler/ts/projects", "ts", ["--module", "--merge-abc"]) 1557 runner.add_directory("compiler/dts", "d.ts", ["--module", "--opt-level=0"]) 1558 runner.add_directory("compiler/commonjs", "js", ["--commonjs"]) 1559 runner.add_directory("parser/concurrent", "js", ["--module"]) 1560 runner.add_directory("parser/js", "js", []) 1561 runner.add_directory("parser/script", "ts", []) 1562 runner.add_directory("parser/ts", "ts", ["--module"]) 1563 runner.add_directory("parser/ts/type_checker", "ts", ["--enable-type-check", "--module"]) 1564 runner.add_directory("parser/commonjs", "js", ["--commonjs"]) 1565 runner.add_directory("parser/binder", "js", ["--dump-assembly", "--dump-literal-buffer", "--module"]) 1566 runner.add_directory("parser/binder", "ts", ["--dump-assembly", "--dump-literal-buffer", "--module"]) 1567 runner.add_directory("parser/binder/noModule", "ts", ["--dump-assembly", "--dump-literal-buffer"]) 1568 runner.add_directory("parser/js/emptySource", "js", []) 1569 runner.add_directory("parser/js/language/arguments-object", "js", []) 1570 runner.add_directory("parser/js/language/statements/for-statement", "js", []) 1571 runner.add_directory("parser/js/language/expressions/optional-chain", "js", []) 1572 runner.add_directory("parser/sendable_class", "ts", ["--module"]) 1573 runner.add_directory("parser/unicode", "js", []) 1574 runner.add_directory("parser/ts/stack_overflow", "ts", []) 1575 1576 runners.append(runner) 1577 1578 1579def add_directory_for_compiler(runners, args): 1580 runner = CompilerRunner(args) 1581 compiler_test_infos = [] 1582 compiler_test_infos.append(CompilerTestInfo("compiler/js", "js", ["--module"])) 1583 compiler_test_infos.append(CompilerTestInfo("compiler/ts/cases", "ts", [])) 1584 compiler_test_infos.append(CompilerTestInfo("compiler/ts/projects", "ts", ["--module"])) 1585 compiler_test_infos.append(CompilerTestInfo("compiler/ts/projects", "ts", ["--module", "--merge-abc"])) 1586 compiler_test_infos.append(CompilerTestInfo("compiler/dts", "d.ts", ["--module", "--opt-level=0"])) 1587 compiler_test_infos.append(CompilerTestInfo("compiler/commonjs", "js", ["--commonjs"])) 1588 compiler_test_infos.append(CompilerTestInfo("compiler/interpreter/lexicalEnv", "js", [])) 1589 compiler_test_infos.append(CompilerTestInfo("compiler/sendable", "ts", ["--module", "--target-api-sub-version=beta3"])) 1590 compiler_test_infos.append(CompilerTestInfo("optimizer/js/branch-elimination", "js", 1591 ["--module", "--branch-elimination", "--dump-assembly"])) 1592 compiler_test_infos.append(CompilerTestInfo("optimizer/js/opt-try-catch-func", "js", 1593 ["--module", "--dump-assembly"])) 1594 compiler_test_infos.append(CompilerTestInfo("compiler/debugInfo/", "js", 1595 ["--debug-info", "--dump-debug-info", "--source-file", "debug-info.js"])) 1596 compiler_test_infos.append(CompilerTestInfo("compiler/js/module-record-field-name-option.js", "js", 1597 ["--module", "--module-record-field-name=abc"])) 1598 compiler_test_infos.append(CompilerTestInfo("compiler/generateCache-projects", "ts", 1599 ["--merge-abc", "--file-threads=0", "--cache-file"])) 1600 # Following directories of test cases are for dump-assembly comparison only, and is not executed. 1601 # Check CompilerProjectTest for more details. 1602 compiler_test_infos.append(CompilerTestInfo("optimizer/ts/branch-elimination/projects", "ts", 1603 ["--module", "--branch-elimination", "--merge-abc", "--dump-assembly", 1604 "--file-threads=8"])) 1605 compiler_test_infos.append(CompilerTestInfo("compiler/bytecodehar/projects", "ts", 1606 ["--merge-abc", "--dump-assembly", "--enable-abc-input", 1607 "--dump-deps-info", "--remove-redundant-file", 1608 "--dump-literal-buffer", "--dump-string", "--abc-class-threads=4"])) 1609 compiler_test_infos.append(CompilerTestInfo("compiler/bytecodehar/js/projects", "js", 1610 ["--merge-abc", "--dump-assembly", "--enable-abc-input", 1611 "--dump-deps-info", "--remove-redundant-file", 1612 "--dump-literal-buffer", "--dump-string", "--abc-class-threads=4"])) 1613 compiler_test_infos.append(CompilerTestInfo("compiler/bytecodehar/merge_abc_consistence_check/projects", "js", 1614 ["--merge-abc", "--dump-assembly", "--enable-abc-input", 1615 "--abc-class-threads=4"])) 1616 1617 compiler_test_infos.append(CompilerTestInfo("compiler/ts/shared_module/projects", "ts", 1618 ["--module", "--merge-abc", "--dump-assembly"])) 1619 1620 if args.enable_arkguard: 1621 prepare_for_obfuscation(compiler_test_infos, runner.test_root) 1622 1623 for info in compiler_test_infos: 1624 runner.add_directory(info.directory, info.extension, info.flags) 1625 1626 runners.append(runner) 1627 1628 1629def add_directory_for_bytecode(runners, args): 1630 runner = BytecodeRunner(args) 1631 runner.add_directory("bytecode/commonjs", "js", ["--commonjs", "--dump-assembly"]) 1632 runner.add_directory("bytecode/js", "js", ["--dump-assembly"]) 1633 runner.add_directory("bytecode/ts/cases", "ts", ["--dump-assembly"]) 1634 runner.add_directory("bytecode/ts/ic", "ts", ["--dump-assembly"]) 1635 runner.add_directory("bytecode/ts/api11", "ts", ["--dump-assembly", "--module", "--target-api-version=11"]) 1636 runner.add_directory("bytecode/ts/api12", "ts", ["--dump-assembly", "--module", "--target-api-version=12"]) 1637 runner.add_directory("bytecode/watch-expression", "js", ["--debugger-evaluate-expression", "--dump-assembly"]) 1638 1639 runners.append(runner) 1640 1641 1642def add_directory_for_debug(runners, args): 1643 runner = RegressionRunner(args) 1644 runner.add_directory("debug/parser", "js", ["--parse-only", "--dump-ast"]) 1645 1646 runners.append(runner) 1647 1648 1649def add_cmd_for_aop_transform(runners, args): 1650 runner = AopTransform(args) 1651 1652 aop_file_path = path.join(runner.test_root, "aop") 1653 lib_suffix = '.so' 1654 #cpp src, deal type, result compare str, abc compare str 1655 msg_list = [ 1656 ["correct_modify.cpp", "compile", "aop_transform_start", "new_abc_content"], 1657 ["correct_no_modify.cpp", "compile", "aop_transform_start", ""], 1658 ["exec_error.cpp", "compile", "Transform exec fail", ""], 1659 ["no_func_transform.cpp", "compile", "os::library_loader::ResolveSymbol get func Transform error", ""], 1660 ["error_format.cpp", "copy_lib", "os::library_loader::Load error", ""], 1661 ["".join(["no_exist", lib_suffix]), "dirct_use", "Failed to find file", ""], 1662 ["error_suffix.xxx", "direct_use", "aop transform file suffix support", ""] 1663 ] 1664 for msg in msg_list: 1665 cpp_file = path.join(aop_file_path, msg[0]) 1666 if msg[1] == 'compile': 1667 lib_file = cpp_file.replace('.cpp', lib_suffix) 1668 remove_file = lib_file 1669 runner.add_cmd(["g++", "--share", "-o", lib_file, cpp_file], "", "", "") 1670 elif msg[1] == 'copy_lib': 1671 lib_file = cpp_file.replace('.cpp', lib_suffix) 1672 remove_file = lib_file 1673 if not os.path.exists(lib_file): 1674 with open(cpp_file, "r") as source_file: 1675 fd = os.open(lib_file, os.O_RDWR | os.O_CREAT | os.O_TRUNC) 1676 target_file = os.fdopen(fd, 'w') 1677 target_file.write(source_file.read()) 1678 elif msg[1] == 'direct_use': 1679 lib_file = cpp_file 1680 remove_file = "" 1681 1682 js_file = path.join(aop_file_path, "test_aop.js") 1683 runner.add_cmd([runner.es2panda, "--merge-abc", "--transform-lib", lib_file, js_file], msg[2], msg[3], remove_file) 1684 1685 runners.append(runner) 1686 1687 1688class AopTransform(Runner): 1689 def __init__(self, args): 1690 Runner.__init__(self, args, "AopTransform") 1691 1692 def add_cmd(self, cmd, compare_str, compare_abc_str, remove_file, func=TestAop): 1693 self.tests += [func(cmd, compare_str, compare_abc_str, remove_file)] 1694 1695 def test_path(self, src): 1696 return src 1697 1698 1699def main(): 1700 args = get_args() 1701 1702 runners = [] 1703 1704 if args.regression: 1705 add_directory_for_regression(runners, args) 1706 1707 if args.abc_to_asm: 1708 add_directory_for_asm(runners, args) 1709 add_directory_for_asm(runners, args, "debug") 1710 1711 if args.tsc: 1712 runners.append(TSCRunner(args)) 1713 1714 if args.compiler: 1715 add_directory_for_compiler(runners, args) 1716 1717 if args.hotfix: 1718 runners.append(HotfixRunner(args)) 1719 1720 if args.hotreload: 1721 runners.append(HotreloadRunner(args)) 1722 1723 if args.coldfix: 1724 runners.append(ColdfixRunner(args)) 1725 1726 if args.coldreload: 1727 runners.append(ColdreloadRunner(args)) 1728 1729 if args.debugger: 1730 runners.append(DebuggerRunner(args)) 1731 1732 if args.base64: 1733 runners.append(Base64Runner(args)) 1734 1735 if args.bytecode: 1736 add_directory_for_bytecode(runners, args) 1737 1738 if args.aop_transform: 1739 add_cmd_for_aop_transform(runners, args) 1740 1741 if args.debug: 1742 add_directory_for_debug(runners, args) 1743 1744 failed_tests = 0 1745 1746 for runner in runners: 1747 runner.run() 1748 failed_tests += runner.summarize() 1749 1750 # TODO: exit 1 when we have failed tests after all tests are fixed 1751 exit(0) 1752 1753 1754if __name__ == "__main__": 1755 main() 1756