1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright (c) 2023-2024 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16 17import os 18import re 19import yaml 20import platform 21import subprocess 22from tool.test_helper import read_declaration 23 24STRICT_OFF = ['--strict', 'false'] 25STRICT_ON = ['--strict', 'true'] 26MODULE = ['--module'] 27DECORATOR = ['--experimentalDecorators'] 28STRICTNULLCHECKS = ['--strictNullChecks'] 29JSX = ['--jsx'] 30 31 32def get_error_message(strs, filename): 33 if platform.system().lower() == 'windows': 34 filename = filename.replace('\\', '/') 35 if len(re.findall(filename + r':(\d+)', strs)) > 0: 36 line_number = re.findall(filename + r':(\d+)', strs) 37 else: 38 line_number = 0 39 err_message = strs 40 return err_message, line_number 41 42 43class TestCase: 44 temp_path = "" 45 ld_library_path = "" 46 js_runtime_path = "" 47 es2abc = "" 48 tsc = "" 49 enable_arkguard = False 50 51 def __init__(self, path): 52 self.path = path 53 self.target_js_path = "" 54 try: 55 data = yaml.safe_load(read_declaration(path)) 56 except: 57 data = {} 58 self.declaration = data 59 self.fail = False 60 self.is_test_case = False if data is None else True 61 self.detail_result = "" 62 self.err_line = 0 63 self.abc_file_path = "" 64 self.abc_file_path_temp = "" 65 66 def execute(self, ark_runtime=False): 67 if not self.is_test_case: 68 return 69 if ark_runtime: 70 with open(self.path, 'a') as file_added: 71 if '.d.ts' not in self.path: 72 file_added.write('\rprint("TESTCASE SUCCESS");') 73 self.__test_es2abc() 74 if os.path.exists(self.abc_file_path): 75 os.remove(self.abc_file_path) 76 else: 77 self.__tsc_test() 78 79 def is_negative(self): 80 if 'error' in self.declaration: 81 return True 82 return False 83 84 def is_current(self): 85 if 'isCurrent' in self.declaration: 86 return True 87 return False 88 89 def experimental_decorators(self): 90 if 'experimentalDecorators' in self.declaration: 91 return True 92 return False 93 94 def null_checks(self): 95 if 'strictNullChecks' in self.declaration: 96 return True 97 return False 98 99 def is_set_module(self): 100 if 'module' in self.declaration: 101 return True 102 return False 103 104 def is_jsx(self): 105 if 'jsx' in self.declaration: 106 return True 107 return False 108 109 def check_declaration(self): 110 if self.declaration == {}: 111 self.detail_result = "parse test case declaration failed, maybe bad format." 112 return False 113 if 'error' in self.declaration: 114 if self.declaration['error'] is None or 'code' not in self.declaration['error'] and 'type' not in \ 115 self.declaration['error']: 116 self.detail_result = "neither error code nor error type are defined in negative case." 117 return False 118 return True 119 120 def __error_code(self): 121 if 'code' in self.declaration['error']: 122 return self.declaration['error']['code'] 123 return None 124 125 def __error_type(self): 126 if 'type' in self.declaration['error']: 127 return self.declaration['error']['type'] 128 return None 129 130 def __get_tsc_cmd(self): 131 if platform.system().lower() == 'windows': 132 cmd = ['cmd', '/c', 'tsc', '--target', 'es2021', '--moduleResolution', 'node'] 133 else: 134 cmd = [TestCase.tsc, '--target', 'es2021', '--moduleResolution', 'node'] 135 if self.__is_strict(): 136 cmd.extend(STRICT_ON) 137 else: 138 cmd.extend(STRICT_OFF) 139 if self.is_set_module(): 140 cmd.extend(MODULE) 141 cmd.append('es2020') 142 if self.experimental_decorators(): 143 cmd.extend(DECORATOR) 144 cmd.append('true') 145 if self.null_checks(): 146 cmd.extend(STRICTNULLCHECKS) 147 cmd.append('false') 148 if self.is_jsx(): 149 cmd.extend(JSX) 150 cmd.append('react-jsx') 151 if self.is_current(): 152 cmd.append(self.path) 153 cmd.append('--outDir') 154 cmd.append(TestCase.temp_path) 155 self.target_js_path = TestCase.temp_path + self.__get_js_basename() 156 return cmd 157 158 def __get_node_cmd(self): 159 cmd = ['node'] 160 if self.is_current(): 161 cmd.append(self.target_js_path) 162 else: 163 cmd.append(TestCase.temp_path + self.__get_js_basename()) 164 return cmd 165 166 # get es2abc --merge-abc 167 def __get_es2abc_cmd(self, file_path): 168 abc_file_path = ("%s.abc" % (os.path.splitext(file_path)[0])) 169 self.abc_file_path_temp = abc_file_path 170 cmd = [TestCase.es2abc + 'es2abc'] 171 if 'RequireCommandrecordsource' in self.path: 172 cmd.extend(['--module', '--record-source', '--output', abc_file_path, file_path]) 173 else: 174 cmd.extend(['--module', '--output', abc_file_path, file_path]) 175 return cmd 176 177 # create abc files 178 def create_abc(self, filename): 179 process = subprocess.Popen(self.__get_es2abc_cmd(filename), stdin=subprocess.PIPE, stdout=subprocess.PIPE, 180 stderr=subprocess.PIPE) 181 out, err = process.communicate(timeout=5000) 182 return_code = process.returncode 183 if return_code != 0: 184 err_msg, line = get_error_message( 185 out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"), filename) 186 self.detail_result = err_msg 187 self.err_line = line 188 self.fail = True 189 return 190 if "TESTCASE SUCCESS" not in out.decode("utf-8", errors="ignore"): 191 self.detail_result = "check stdout failed!" 192 self.fail = True 193 return 194 195 # get es2abc file commands 196 def _get_ark_js_cmd(self): 197 os.environ.setdefault("LD_LIBRARY_PATH", TestCase.ld_library_path) 198 run_abc_cmd = [os.path.join(TestCase.js_runtime_path, 'ark_js_vm'), self.abc_file_path_temp] 199 return run_abc_cmd 200 pass 201 202 def __get_js_basename(self): 203 sp = '/' 204 if platform.system().lower() == 'windows': 205 sp = '\\' 206 return "test_ts_cases" + sp + self.path.split(sp + "test_ts_cases" + sp)[1].replace('.tsx', '.js').replace('.ts', '.js') 207 208 def __is_strict(self): 209 if 'strict' in self.declaration: 210 return bool(self.declaration['strict']) 211 return True 212 213 def __tsc_test(self): 214 process = subprocess.Popen(self.__get_tsc_cmd(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, 215 stderr=subprocess.PIPE) 216 out, err = process.communicate(timeout=5000) 217 return_code = process.returncode 218 if self.is_negative(): 219 if return_code == 0: 220 self.fail = True 221 self.detail_result = "No error found in negative case." 222 return 223 if self.__error_code() in out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"): 224 return 225 self.fail = True 226 self.detail_result = "Error code not as expected." 227 return 228 # positive case 229 if return_code != 0: 230 self.detail_result = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 231 self.fail = True 232 return 233 if self.is_current(): 234 with open(self.target_js_path, 'a') as fileAdded: 235 fileAdded.write('console.log("TESTCASE SUCCESS");') 236 # run node command 237 process = subprocess.Popen(self.__get_node_cmd(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, 238 stderr=subprocess.PIPE) 239 out, err = process.communicate(timeout=5000) 240 return_code = process.returncode 241 if self.is_current(): 242 if os.path.exists(self.target_js_path): 243 os.remove(self.target_js_path) 244 if return_code != 0: 245 err_msg, line = get_error_message( 246 out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"), self.__get_js_basename()) 247 self.detail_result = err_msg 248 self.err_line = line 249 self.fail = True 250 return 251 # check std out 252 if "TESTCASE SUCCESS" not in out.decode("utf-8", errors="ignore"): 253 self.detail_result = "check stdout failed!" 254 self.fail = True 255 return 256 257 258 def execute_arkguard(self, input_file_path): 259 arkguard_root_dir = os.path.join("../../../../", "arkcompiler/ets_frontend/arkguard") 260 arkgurad_entry_path = os.path.join(arkguard_root_dir, "lib/cli/SecHarmony.js") 261 config_path = os.path.join(arkguard_root_dir, "test/compilerTestConfig.json") 262 arkguard_cmd = [ 263 'node', 264 '--no-warnings', 265 arkgurad_entry_path, 266 input_file_path, 267 '--config-path', 268 config_path, 269 '--inplace' 270 ] 271 # print(arkguard_cmd) 272 process = subprocess.Popen(arkguard_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 273 out, err = process.communicate() 274 if err: 275 print("arkguard error: ", err) 276 process.wait() 277 278 279 def __test_es2abc(self): 280 # run arkguard 281 if TestCase.enable_arkguard: 282 self.execute_arkguard(self.path) 283 284 # compiler to abc 285 process = subprocess.Popen(self.__get_es2abc_cmd(self.path), stdin=subprocess.PIPE, stdout=subprocess.PIPE, 286 stderr=subprocess.PIPE) 287 out, err = process.communicate(timeout=5000) 288 return_code = process.returncode 289 if self.is_negative(): 290 if return_code == 0: 291 self.fail = True 292 return 293 if self.__error_type() in out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"): 294 return 295 self.fail = True 296 self.detail_result = "Error type not as expected." 297 return 298 # positive case 299 if return_code != 0: 300 self.detail_result = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore") 301 self.fail = True 302 return 303 # execute ark_js_vm 304 process = subprocess.Popen(self._get_ark_js_cmd(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, 305 stderr=subprocess.PIPE) 306 out, err = process.communicate(timeout=5000) 307 return_code = process.returncode 308 if return_code != 0: 309 err_msg, line = get_error_message( 310 out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"), 311 os.path.basename(self.abc_file_path)) 312 self.detail_result = err_msg 313 self.err_line = line 314 self.fail = True 315 return 316 # check std out 317 if "TESTCASE SUCCESS" not in out.decode("utf-8", errors="ignore") and '.d.ts' not in self.path: 318 self.detail_result = "check stdout failed!" 319 self.fail = True 320 return 321