• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 check_declaration(self):
67        if self.declaration == {}:
68            self.detail_result = "parse test case declaration failed, maybe bad format."
69            return False
70        if 'error' in self.declaration:
71            if self.declaration['error'] is None or 'code' not in self.declaration['error'] and 'type' not in \
72                    self.declaration['error']:
73                self.detail_result = "neither error code nor error type are defined in negative case."
74                return False
75        return True
76
77    # create abc files
78    def create_abc(self, filename):
79        process = subprocess.Popen(self.__get_es2abc_cmd(filename), stdin=subprocess.PIPE, stdout=subprocess.PIPE,
80                                   stderr=subprocess.PIPE)
81        out, err = process.communicate(timeout=5000)
82        return_code = process.returncode
83        if return_code != 0:
84            err_msg, line = get_error_message(
85                out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"), filename)
86            self.detail_result = err_msg
87            self.err_line = line
88            self.fail = True
89            return
90        if "TESTCASE SUCCESS" not in out.decode("utf-8", errors="ignore"):
91            self.detail_result = "check stdout failed!"
92            self.fail = True
93            return
94
95    def execute(self, ark_runtime=False):
96        if not self.is_test_case:
97            return
98        if ark_runtime:
99            with open(self.path, 'a') as file_added:
100                if '.d.ts' not in self.path:
101                    file_added.write('\rprint("TESTCASE SUCCESS");')
102            self.__test_es2abc()
103            if os.path.exists(self.abc_file_path):
104                os.remove(self.abc_file_path)
105        else:
106            self.__tsc_test()
107
108    def execute_arkguard(self, input_file_path):
109        arkguard_root_dir = os.path.join("../../../../", "arkcompiler/ets_frontend/arkguard")
110        arkgurad_entry_path = os.path.join(arkguard_root_dir, "lib/cli/SecHarmony.js")
111        config_path = os.path.join(arkguard_root_dir, "test/compilerTestConfig.json")
112        arkguard_cmd = [
113            'node',
114            '--no-warnings',
115            arkgurad_entry_path,
116            input_file_path,
117            '--config-path',
118            config_path,
119            '--inplace'
120        ]
121
122        process = subprocess.Popen(arkguard_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
123        out, err = process.communicate()
124        if err:
125            print("arkguard error: ", err)
126        process.wait()
127
128    def experimental_decorators(self):
129        if 'experimentalDecorators' in self.declaration:
130            return True
131        return False
132
133    def is_negative(self):
134        if 'error' in self.declaration:
135            return True
136        return False
137
138    def is_current(self):
139        if 'isCurrent' in self.declaration:
140            return True
141        return False
142
143    def null_checks(self):
144        if 'strictNullChecks' in self.declaration:
145            return True
146        return False
147
148    def is_set_module(self):
149        if 'module' in self.declaration:
150            return True
151        return False
152
153    def is_jsx(self):
154        if 'jsx' in self.declaration:
155            return True
156        return False
157
158    def __error_code(self):
159        if 'code' in self.declaration['error']:
160            return self.declaration['error']['code']
161        return None
162
163    def __error_type(self):
164        if 'type' in self.declaration['error']:
165            return self.declaration['error']['type']
166        return None
167
168    def __get_tsc_cmd(self):
169        if platform.system().lower() == 'windows':
170            cmd = ['cmd', '/c', 'tsc', '--target', 'es2021', '--moduleResolution', 'node']
171        else:
172            cmd = [TestCase.tsc, '--target', 'es2021', '--moduleResolution', 'node']
173        if self.__is_strict():
174            cmd.extend(STRICT_ON)
175        else:
176            cmd.extend(STRICT_OFF)
177        if self.is_set_module():
178            cmd.extend(MODULE)
179            cmd.append('es2020')
180        if self.experimental_decorators():
181            cmd.extend(DECORATOR)
182            cmd.append('true')
183        if self.null_checks():
184            cmd.extend(STRICTNULLCHECKS)
185            cmd.append('false')
186        if self.is_jsx():
187            cmd.extend(JSX)
188            cmd.append('react-jsx')
189        if self.is_current():
190            cmd.append(self.path)
191            cmd.append('--outDir')
192            cmd.append(TestCase.temp_path)
193            self.target_js_path = TestCase.temp_path + self.__get_js_basename()
194        return cmd
195
196    def __get_node_cmd(self):
197        cmd = ['node']
198        if self.is_current():
199            cmd.append(self.target_js_path)
200        else:
201            cmd.append(TestCase.temp_path + self.__get_js_basename())
202        return cmd
203
204    # get es2abc --merge-abc
205    def __get_es2abc_cmd(self, file_path):
206        abc_file_path = ("%s.abc" % (os.path.splitext(file_path)[0]))
207        self.abc_file_path_temp = abc_file_path
208        cmd = [TestCase.es2abc + 'es2abc']
209        if 'RequireCommandrecordsource' in self.path:
210            cmd.extend(['--module', '--record-source', '--output', abc_file_path, file_path])
211        else:
212            cmd.extend(['--module', '--output', abc_file_path, file_path])
213        return cmd
214
215    # get es2abc file commands
216    def _get_ark_js_cmd(self):
217        os.environ.setdefault("LD_LIBRARY_PATH", TestCase.ld_library_path)
218        run_abc_cmd = [os.path.join(TestCase.js_runtime_path, 'ark_js_vm'), self.abc_file_path_temp]
219        return run_abc_cmd
220        pass
221
222    def __get_js_basename(self):
223        sp = '/'
224        if platform.system().lower() == 'windows':
225            sp = '\\'
226        return "test_ts_cases" + sp + self.path.split(sp + "test_ts_cases" + sp)[1].replace('.tsx', '.js').replace('.ts', '.js')
227
228    def __is_strict(self):
229        if 'strict' in self.declaration:
230            return bool(self.declaration['strict'])
231        return True
232
233    def __tsc_test(self):
234        process = subprocess.Popen(self.__get_tsc_cmd(), stdin=subprocess.PIPE, stdout=subprocess.PIPE,
235                                   stderr=subprocess.PIPE)
236        out, err = process.communicate(timeout=5000)
237        return_code = process.returncode
238        if self.is_negative():
239            if return_code == 0:
240                self.fail = True
241                self.detail_result = "No error found in negative case."
242                return
243            if self.__error_code() in out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"):
244                return
245            self.fail = True
246            self.detail_result = "Error code not as expected."
247            return
248        # positive case
249        if return_code != 0:
250            self.detail_result = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore")
251            self.fail = True
252            return
253        if self.is_current():
254            with open(self.target_js_path, 'a') as fileAdded:
255                fileAdded.write('console.log("TESTCASE SUCCESS");')
256        # run node command
257        process = subprocess.Popen(self.__get_node_cmd(), stdin=subprocess.PIPE, stdout=subprocess.PIPE,
258                                   stderr=subprocess.PIPE)
259        out, err = process.communicate(timeout=5000)
260        return_code = process.returncode
261        if self.is_current():
262            if os.path.exists(self.target_js_path):
263                os.remove(self.target_js_path)
264        if return_code != 0:
265            err_msg, line = get_error_message(
266                out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"), self.__get_js_basename())
267            self.detail_result = err_msg
268            self.err_line = line
269            self.fail = True
270            return
271        # check std out
272        if "TESTCASE SUCCESS" not in out.decode("utf-8", errors="ignore"):
273            self.detail_result = "check stdout failed!"
274            self.fail = True
275            return
276
277
278    def __test_es2abc(self):
279        # run arkguard
280        if TestCase.enable_arkguard:
281            self.execute_arkguard(self.path)
282
283        # compiler to abc
284        process = subprocess.Popen(self.__get_es2abc_cmd(self.path), stdin=subprocess.PIPE, stdout=subprocess.PIPE,
285                                   stderr=subprocess.PIPE)
286        out, err = process.communicate(timeout=5000)
287        return_code = process.returncode
288        if self.is_negative():
289            if return_code == 0:
290                self.fail = True
291                return
292            if self.__error_type() in out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"):
293                return
294            self.fail = True
295            self.detail_result = "Error type not as expected."
296            return
297        # positive case
298        if return_code != 0:
299            self.detail_result = out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore")
300            self.fail = True
301            return
302        # execute ark_js_vm
303        process = subprocess.Popen(self._get_ark_js_cmd(), stdin=subprocess.PIPE, stdout=subprocess.PIPE,
304                                   stderr=subprocess.PIPE)
305        out, err = process.communicate(timeout=5000)
306        return_code = process.returncode
307        if return_code != 0:
308            err_msg, line = get_error_message(
309                out.decode("utf-8", errors="ignore") + err.decode("utf-8", errors="ignore"),
310                os.path.basename(self.abc_file_path))
311            self.detail_result = err_msg
312            self.err_line = line
313            self.fail = True
314            return
315        # check std out
316        if "TESTCASE SUCCESS" not in out.decode("utf-8", errors="ignore") and '.d.ts' not in self.path:
317            self.detail_result = "check stdout failed!"
318            self.fail = True
319            return