• 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 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