• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16
17const ts = require('typescript');
18const path = require('path');
19const fs = require('fs')
20
21
22const ignoreCaseFilePath= path.join(__dirname, "ignorecase.json")
23const compResults = {"detail":{}, 'failNum':0, "passedNum":0}
24let consoleDetail = false;
25let ignoreList = [];
26let failTestCaseList = [];
27let genResultFile = false;
28let arktsVersion = '1.1';
29// Traverse the directory to find all test cases
30function getAllETSFiles(filePath) {
31  let allFilePaths = [];
32  if (fs.existsSync(filePath)) {
33      const files = fs.readdirSync(filePath);
34      for (let i = 0; i < files.length; i++) {
35          let file = files[i]; // File name (excluding file path)
36          let currentFilePath = filePath + '/' + file;
37          let stats = fs.lstatSync(currentFilePath);
38          if(ignoreList.includes(currentFilePath)){
39            continue
40          }
41          if (stats.isDirectory()) {
42              allFilePaths = allFilePaths.concat(getAllETSFiles(currentFilePath));
43          } else {
44              var index= currentFilePath.lastIndexOf(".");
45              var ext = currentFilePath.substring(index+1);
46              if (ext === 'ets' || ext === 'ts') {
47                allFilePaths.push(currentFilePath);
48                runComp(currentFilePath, file)
49              }
50          }
51      }
52  } else {
53      console.warn(`The specified directory ${filePath} Non-existent!`);
54  }
55  return allFilePaths;
56}
57
58function runComp(currentFilePath, file){
59    const result = runLinter(currentFilePath)
60    let jsonFile = currentFilePath.replace('.ets', '.json');
61    jsonFile = jsonFile.replace('.ts', '.json');
62    const checkfile = fs.existsSync(jsonFile);
63    if(checkfile){
64      loadPares(jsonFile, result, currentFilePath, file)
65    }else{
66      if(!currentFilePath.includes("-dependencie.ets")){
67        console.log(`Test cases ${currentFilePath} expected results are not added`)
68      }
69    }
70}
71
72function forceUpdateExpected(expect, reality, jsonFile) {
73  let updateArray = [];
74  for (let i = 0; i < reality.length; i++) {
75    const realErrorItem = reality[i];
76    const { line, character } = realErrorItem.file.getLineAndCharacterOfPosition(realErrorItem.start);
77    const realLine = { 'line': line + 1, 'character': character + 1 };
78    const realMessageText = typeof (realErrorItem.messageText) === 'string' ? realErrorItem.messageText : realErrorItem.messageText.messageText;
79    let data = {
80      messageText: realMessageText,
81      expectLineAndCharacter: realLine
82    };
83    updateArray.push(data);
84  }
85  if (arktsVersion === '1.0') {
86    expect.arktsVersion_1_0 = updateArray;
87  } else {
88    expect.arktsVersion_1_1 = updateArray;
89  }
90  let s = JSON.stringify(expect, null, 2);
91  fs.writeFileSync(jsonFile, s);
92}
93
94// Compare the results with expectations and count the success and failure situations
95function loadPares(jsonFile, result, currentFilePath, file){
96  const dirName = path.dirname(currentFilePath)
97  let rules = ""
98  if (dirName.includes("\\")){
99    rules = currentFilePath.split("\\")[currentFilePath.split("\\").length - 2]
100  }else{
101    rules = currentFilePath.split("/")[currentFilePath.split("/").length - 2]
102  }
103  const testCaseFileName = file
104  dataStr = fs.readFileSync(jsonFile, "utf-8")
105  const expect = JSON.parse(dataStr)
106  // if need update expected files, insert forceUpdateExpected(expect, result, jsonFile) here.
107  let expectByVersion = arktsVersion === '1.0' ? expect.arktsVersion_1_0 : expect.arktsVersion_1_1;
108  if (expectByVersion === undefined) {
109    expectByVersion = [];
110  }
111
112  const compResult = compareResult(expectByVersion, result);
113  compResult["testCaseName"] = testCaseFileName
114  if (Object.prototype.hasOwnProperty.call(compResults.detail, rules)) {
115    compResults["detail"][rules]["detail"].push(compResult)
116    compResults["detail"][rules]["testCaseNum"] += 1
117  }else{
118    compResults["detail"][rules] = {"detail":[compResult], "testCaseNum": 1, "failNum": 0, "passedNum": 0}
119  }
120  if(compResult.status){
121    compResults["passedNum"] += 1
122    compResults["detail"][rules]["passedNum"] += 1
123  }else{
124    failTestCaseList.push(currentFilePath)
125    if(consoleDetail){
126      console.log(`Test cases ${currentFilePath} Failed!`)
127      for(let compDetail of compResult.detail){
128        if(!compDetail.compResult){
129          console.log(`==>  Expect the error in Line ${compDetail.expectLineAndCharacter.line} The ${compDetail.expectLineAndCharacter.character} character. Expect exception rules:${compDetail.expectMessageText}  Actual error line ${compDetail.realLineAndCharacter.line}  The ${compDetail.realLineAndCharacter.character} character. Actual exception rules:${compDetail.realMessageText} Comparison Result:Fail!`)
130        }
131      }
132    }
133    compResults["failNum"] += 1
134    compResults['detail'][rules]["failNum"] += 1
135  }
136}
137
138
139// initial configuration
140options = ts.readConfigFile('tsconfig.json', ts.sys.readFile).config.compilerOptions;
141const allPath = ['*'];
142Object.assign(options, {
143  'emitNodeModulesFiles': true,
144  'importsNotUsedAsValues': ts.ImportsNotUsedAsValues.Preserve,
145  'module': ts.ModuleKind.ES2020,
146  'moduleResolution': ts.ModuleResolutionKind.NodeJs,
147  'noEmit': true,
148  'target': ts.ScriptTarget.ES2021,
149  'baseUrl': "/",
150  'paths': {
151    '*': allPath
152  },
153  'lib': [
154    'lib.es2021.d.ts'
155  ],
156  'types': [],
157  'etsLoaderPath': 'null_sdkPath',
158});
159
160// Calling the runlinter interface
161function runLinter(rootName) {
162  nonStrictCheckParam = {
163    allowJS: true,
164    checkJs: false
165  };
166  Object.assign(options, nonStrictCheckParam);
167  builderProgram = ts.createIncrementalProgramForArkTs({
168      rootNames: [path.join(process.cwd(), rootName)],
169      options: options,
170    });
171
172  let result = arktsVersion === '1.0' ? ts.ArkTSLinter_1_0.runArkTSLinter(builderProgram) : ts.ArkTSLinter_1_1.runArkTSLinter(builderProgram);
173  return result;
174}
175
176// Compare the difference between the expected value and the actual return value of the runlinter to determine if the test has passed
177function compareResult(expect, reality){
178  let isPass = true
179  const itemPassList = new Array()
180   if(reality.length == 0){
181      if(expect.length == 0){
182        // pass
183        isPass = true
184      }else{
185        isPass = false
186        for(let expectInfo of expect){
187          const compInfo = {
188            'compResult':false,
189            'realLineAndCharacter':{"line": null,"character": null},
190            'realMessageText':null,
191            'expectLineAndCharacter':{"line": expectInfo.expectLineAndCharacter.line,"character": expectInfo.expectLineAndCharacter.character},
192            'expectMessageText':expectInfo.messageText,
193          }
194          itemPassList.push(compInfo)
195        }
196      }
197   }else{
198      if(expect.length == 0){
199        isPass = false
200        for(let realityInfo of reality){
201            const { line, character } = realityInfo.file.getLineAndCharacterOfPosition(realityInfo.start)
202            const compInfo = {
203              'compResult':false,
204              'realLineAndCharacter':{"line": line + 1,"character": character + 1},
205              'realMessageText':realityInfo.messageText,
206              'expectLineAndCharacter':{"line": null,"character": null},
207              'expectMessageText':null,
208            }
209            itemPassList.push(compInfo)
210        }
211      }else{
212        if( reality.length > expect.length){
213          isPass = false
214          for(let i=0; i<reality.length; i++){
215            const realErrorItem = reality[i]
216            const { line, character } = realErrorItem.file.getLineAndCharacterOfPosition(realErrorItem.start)
217            const realLine = {"line": line + 1,"character": character + 1}
218            const realMessageText = typeof (realErrorItem.messageText) === 'string' ? realErrorItem.messageText : realErrorItem.messageText.messageText;
219            let expectMessageText = null
220            let compResult = false
221            let expectLineAndCharacter = {"line": null,"character": null}
222            if( expect.length < i+1){
223              compResult = false
224            }else{
225              expectErrorItem = expect[i]
226              expectLineAndCharacter = {"line": expectErrorItem.expectLineAndCharacter.line,"character": expectErrorItem.expectLineAndCharacter.character}
227              expectMessageText = expectErrorItem.messageText
228              if ((expectErrorItem.expectLineAndCharacter.line === realLine.line && expectErrorItem.expectLineAndCharacter.character === realLine.character) &&
229                realMessageText === expectMessageText) {
230                compResult = true
231              }
232            }
233            const compInfo = {
234              'compResult':compResult,
235              'realLineAndCharacter':realLine,
236              'realMessageText':realMessageText,
237              'expectLineAndCharacter':expectLineAndCharacter,
238              'expectMessageText':expectMessageText,
239            }
240            itemPassList.push(compInfo)
241          }
242        }else if(reality.length < expect.length){
243          isPass = false
244          for(let i=0; i<expect.length; i++){
245            const expectErrorItem = expect[i]
246            const expectMessageText = expectErrorItem.messageText
247            let expectLineAndCharacter = {"line": expectErrorItem.expectLineAndCharacter.line,"character": expectErrorItem.expectLineAndCharacter.character}
248            let realLine = {"line": null,"character": null}
249            let realMessageText = null
250            let compResult = false
251            if( reality.length < i+1){
252              compResult = false
253            }else{
254              const realErrorItem = reality[i]
255              const { line, character } = realErrorItem.file.getLineAndCharacterOfPosition(realErrorItem.start)
256              realLine = {"line": line + 1,"character": character + 1}
257              realMessageText = typeof (realErrorItem.messageText) === 'string' ? realErrorItem.messageText : realErrorItem.messageText.messageText;
258              if ((expectErrorItem.expectLineAndCharacter.line === realLine.line && expectErrorItem.expectLineAndCharacter.character === realLine.character) &&
259                realMessageText === expectMessageText) {
260                compResult = true
261              }
262            }
263            const compInfo = {
264              'compResult':compResult,
265              'realLineAndCharacter':realLine,
266              'realMessageText':realMessageText,
267              'expectLineAndCharacter':expectLineAndCharacter,
268              'expectMessageText':expectMessageText,
269            }
270            itemPassList.push(compInfo)
271          }
272        }else{
273            for(let i =0;i<reality.length;i++){
274              const realErrorItem = reality[i]
275              const expectErrorItem = expect[i]
276              const expectMessageText = expectErrorItem.messageText
277              let expectLineAndCharacter = {"line": expectErrorItem.expectLineAndCharacter.line,"character": expectErrorItem.expectLineAndCharacter.character}
278              const { line, character } = realErrorItem.file.getLineAndCharacterOfPosition(realErrorItem.start)
279              const realLine = {"line": line + 1,"character": character + 1}
280              const realMessageText = typeof (realErrorItem.messageText) === 'string' ? realErrorItem.messageText : realErrorItem.messageText.messageText;
281              let compInfo = null; compResult = false
282              if ((expectErrorItem.expectLineAndCharacter.line === realLine.line && expectErrorItem.expectLineAndCharacter.character === realLine.character) &&
283                realMessageText === expectMessageText) {
284                compResult = true
285              }else{
286                isPass = false
287              }
288              compInfo = {
289                'compResult':compResult,
290                'realLineAndCharacter':realLine,
291                'realMessageText':realMessageText,
292                'expectLineAndCharacter':expectLineAndCharacter,
293                'expectMessageText':expectMessageText,
294              }
295              itemPassList.push(compInfo)
296            }
297      }
298    }
299  }
300  return {"status":isPass, "detail":itemPassList}
301}
302
303// output result file
304function writeResult(result){
305  const dir = path.join(__dirname, "test_results")
306  if (!fs.existsSync(dir)) {
307    fs.mkdirSync(dir)
308  }
309  fs.writeFileSync(path.join(dir, "test_result.json"), JSON.stringify(result, null, 4))
310}
311
312
313function run(){
314   let interval = 0, startTime = process.uptime()*1000, endTime = startTime;
315   const pathParam = getParam()
316   let filePath = 'testcase'
317   if(pathParam){
318    filePath = pathParam
319   }
320   let ignoreCaseConfigList = []
321   if(fs.existsSync(ignoreCaseFilePath)){
322    ignoreCaseConfigList = JSON.parse(fs.readFileSync(ignoreCaseFilePath)).ignoreCase
323   }
324
325   ignoreList = ignoreList.concat(ignoreCaseConfigList)
326   let filePathStats = fs.lstatSync(filePath)
327   if(!filePathStats.isDirectory()){
328      runComp(filePath, path.basename(filePath))
329   }else{
330      getAllETSFiles(filePath)
331   }
332   endTime = process.uptime()*1000
333   interval = (endTime - startTime);
334   const compReportDetail = {"compDetail": compResults, "compTime": interval, "failNum": compResults.failNum, "passedNum": compResults.passedNum}
335   const testCaseSum = compReportDetail.failNum + compReportDetail.passedNum
336   compReportDetail["testCaseSum"] = testCaseSum
337   console.log(`Total number of test cases:${testCaseSum} Number of use cases passed:${compResults.passedNum} The number of use cases that failed:${compResults.failNum} Total running time:${JSON.stringify(interval).split(".")[0]}ms`)
338   if(genResultFile){
339     writeResult(compReportDetail)
340   }
341   if (failTestCaseList.length > 0){
342      console.log("Failed test cases:")
343      for(let testCase of failTestCaseList){
344        console.log(testCase)
345      }
346    }
347   if(ignoreList.length>0){
348    console.log("Ignored test cases:")
349    for(let ignoreCase of ignoreList){
350      console.log(ignoreCase)
351    }
352   }
353   if(compReportDetail.failNum){
354    process.exit(1)
355   }
356}
357
358// get parameters
359function getParam(){
360  let pathArg = null
361  for(let key of process.argv){
362    if(key.includes("-P:")){
363      pathArg = key.replace("-P:", "")
364    }
365    if(key === "--detail" || key === "-D"){
366      consoleDetail = true
367    }
368    if(key === "-e"){
369      genResultFile = true
370    }
371    if(key.includes("--ignore-list:")){
372      let ignoreStr = key.replace("--ignore-list:", "")
373      ignoreList = ignoreStr.split(",")
374    }
375    if (key === '-v1.0') {
376      arktsVersion = '1.0';
377    }
378    if (key === '-v1.1') {
379      arktsVersion = '1.1';
380    }
381  }
382  return pathArg
383}
384
385// execute
386run()
387