• 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 = path.join(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') || ignoreList.includes(currentFilePath)) {
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  'compatibleSdkVersion': 12,
159  'compatibleSdkVersionStage': 'beta3'
160});
161
162// Calling the runlinter interface
163function runLinter(rootName) {
164  nonStrictCheckParam = {
165    allowJS: true,
166    checkJs: false
167  };
168  Object.assign(options, nonStrictCheckParam);
169  builderProgram = ts.createIncrementalProgramForArkTs({
170      rootNames: [path.join(process.cwd(), rootName)],
171      options: options,
172    });
173
174  let result = arktsVersion === '1.0' ? ts.ArkTSLinter_1_0.runArkTSLinter(builderProgram) : ts.ArkTSLinter_1_1.runArkTSLinter(builderProgram);
175  return result;
176}
177
178// Compare the difference between the expected value and the actual return value of the runlinter to determine if the test has passed
179function compareResult(expect, reality){
180  let isPass = true
181  const itemPassList = new Array()
182   if(reality.length == 0){
183      if(expect.length == 0){
184        // pass
185        isPass = true
186      }else{
187        isPass = false
188        for(let expectInfo of expect){
189          const compInfo = {
190            'compResult':false,
191            'realLineAndCharacter':{"line": null,"character": null},
192            'realMessageText':null,
193            'expectLineAndCharacter':{"line": expectInfo.expectLineAndCharacter.line,"character": expectInfo.expectLineAndCharacter.character},
194            'expectMessageText':expectInfo.messageText,
195          }
196          itemPassList.push(compInfo)
197        }
198      }
199   }else{
200      if(expect.length == 0){
201        isPass = false
202        for(let realityInfo of reality){
203            const { line, character } = realityInfo.file.getLineAndCharacterOfPosition(realityInfo.start)
204            const compInfo = {
205              'compResult':false,
206              'realLineAndCharacter':{"line": line + 1,"character": character + 1},
207              'realMessageText':realityInfo.messageText,
208              'expectLineAndCharacter':{"line": null,"character": null},
209              'expectMessageText':null,
210            }
211            itemPassList.push(compInfo)
212        }
213      }else{
214        if( reality.length > expect.length){
215          isPass = false
216          for(let i=0; i<reality.length; i++){
217            const realErrorItem = reality[i]
218            const { line, character } = realErrorItem.file.getLineAndCharacterOfPosition(realErrorItem.start)
219            const realLine = {"line": line + 1,"character": character + 1}
220            const realMessageText = typeof (realErrorItem.messageText) === 'string' ? realErrorItem.messageText : realErrorItem.messageText.messageText;
221            let expectMessageText = null
222            let compResult = false
223            let expectLineAndCharacter = {"line": null,"character": null}
224            if( expect.length < i+1){
225              compResult = false
226            }else{
227              expectErrorItem = expect[i]
228              expectLineAndCharacter = {"line": expectErrorItem.expectLineAndCharacter.line,"character": expectErrorItem.expectLineAndCharacter.character}
229              expectMessageText = expectErrorItem.messageText
230              if ((expectErrorItem.expectLineAndCharacter.line === realLine.line && expectErrorItem.expectLineAndCharacter.character === realLine.character) &&
231                realMessageText === expectMessageText) {
232                compResult = true
233              }
234            }
235            const compInfo = {
236              'compResult':compResult,
237              'realLineAndCharacter':realLine,
238              'realMessageText':realMessageText,
239              'expectLineAndCharacter':expectLineAndCharacter,
240              'expectMessageText':expectMessageText,
241            }
242            itemPassList.push(compInfo)
243          }
244        }else if(reality.length < expect.length){
245          isPass = false
246          for(let i=0; i<expect.length; i++){
247            const expectErrorItem = expect[i]
248            const expectMessageText = expectErrorItem.messageText
249            let expectLineAndCharacter = {"line": expectErrorItem.expectLineAndCharacter.line,"character": expectErrorItem.expectLineAndCharacter.character}
250            let realLine = {"line": null,"character": null}
251            let realMessageText = null
252            let compResult = false
253            if( reality.length < i+1){
254              compResult = false
255            }else{
256              const realErrorItem = reality[i]
257              const { line, character } = realErrorItem.file.getLineAndCharacterOfPosition(realErrorItem.start)
258              realLine = {"line": line + 1,"character": character + 1}
259              realMessageText = typeof (realErrorItem.messageText) === 'string' ? realErrorItem.messageText : realErrorItem.messageText.messageText;
260              if ((expectErrorItem.expectLineAndCharacter.line === realLine.line && expectErrorItem.expectLineAndCharacter.character === realLine.character) &&
261                realMessageText === expectMessageText) {
262                compResult = true
263              }
264            }
265            const compInfo = {
266              'compResult':compResult,
267              'realLineAndCharacter':realLine,
268              'realMessageText':realMessageText,
269              'expectLineAndCharacter':expectLineAndCharacter,
270              'expectMessageText':expectMessageText,
271            }
272            itemPassList.push(compInfo)
273          }
274        }else{
275            for(let i =0;i<reality.length;i++){
276              const realErrorItem = reality[i]
277              const expectErrorItem = expect[i]
278              const expectMessageText = expectErrorItem.messageText
279              let expectLineAndCharacter = {"line": expectErrorItem.expectLineAndCharacter.line,"character": expectErrorItem.expectLineAndCharacter.character}
280              const { line, character } = realErrorItem.file.getLineAndCharacterOfPosition(realErrorItem.start)
281              const realLine = {"line": line + 1,"character": character + 1}
282              const realMessageText = typeof (realErrorItem.messageText) === 'string' ? realErrorItem.messageText : realErrorItem.messageText.messageText;
283              let compInfo = null; compResult = false
284              if ((expectErrorItem.expectLineAndCharacter.line === realLine.line && expectErrorItem.expectLineAndCharacter.character === realLine.character) &&
285                realMessageText === expectMessageText) {
286                compResult = true
287              }else{
288                isPass = false
289              }
290              compInfo = {
291                'compResult':compResult,
292                'realLineAndCharacter':realLine,
293                'realMessageText':realMessageText,
294                'expectLineAndCharacter':expectLineAndCharacter,
295                'expectMessageText':expectMessageText,
296              }
297              itemPassList.push(compInfo)
298            }
299      }
300    }
301  }
302  return {"status":isPass, "detail":itemPassList}
303}
304
305// output result file
306function writeResult(result){
307  const dir = path.join(__dirname, "test_results")
308  if (!fs.existsSync(dir)) {
309    fs.mkdirSync(dir)
310  }
311  fs.writeFileSync(path.join(dir, "test_result.json"), JSON.stringify(result, null, 4))
312}
313
314
315function run(){
316   let interval = 0, startTime = process.uptime()*1000, endTime = startTime;
317   const pathParam = getParam()
318   let filePath = 'testcase'
319   if(pathParam){
320    filePath = pathParam
321   }
322   let ignoreCaseConfigList = []
323   if(fs.existsSync(ignoreCaseFilePath)){
324    ignoreCaseConfigList = JSON.parse(fs.readFileSync(ignoreCaseFilePath)).ignoreCase
325   }
326
327   ignoreList = ignoreList.concat(ignoreCaseConfigList).map(x => path.normalize(x));
328
329   let filePathStats = fs.lstatSync(filePath)
330   if(!filePathStats.isDirectory()){
331      runComp(filePath, path.basename(filePath))
332   }else{
333      getAllETSFiles(filePath)
334   }
335   endTime = process.uptime()*1000
336   interval = (endTime - startTime);
337   const compReportDetail = {"compDetail": compResults, "compTime": interval, "failNum": compResults.failNum, "passedNum": compResults.passedNum}
338   const testCaseSum = compReportDetail.failNum + compReportDetail.passedNum
339   compReportDetail["testCaseSum"] = testCaseSum
340   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. ArkTSVersion: ${arktsVersion}`)
341   if(genResultFile){
342     writeResult(compReportDetail)
343   }
344   if (failTestCaseList.length > 0){
345      console.log("Failed test cases:")
346      for(let testCase of failTestCaseList){
347        console.log(testCase)
348      }
349    }
350   if(ignoreList.length>0){
351    console.log("Ignored test cases:")
352    for(let ignoreCase of ignoreList){
353      console.log(ignoreCase)
354    }
355   }
356   if(compReportDetail.failNum){
357    process.exit(1)
358   }
359}
360
361// get parameters
362function getParam(){
363  let pathArg = null
364  for(let key of process.argv){
365    if(key.includes("-P:")){
366      pathArg = key.replace("-P:", "")
367    }
368    if(key === "--detail" || key === "-D"){
369      consoleDetail = true
370    }
371    if(key === "-e"){
372      genResultFile = true
373    }
374    if(key.includes("--ignore-list:")){
375      let ignoreStr = key.replace("--ignore-list:", "")
376      ignoreList = ignoreStr.split(",")
377    }
378    if (key === '-v1.0') {
379      arktsVersion = '1.0';
380    }
381    if (key === '-v1.1') {
382      arktsVersion = '1.1';
383    }
384  }
385  return pathArg
386}
387
388// execute
389run()
390