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
16import { expect } from 'chai';
17import path from 'path';
18import fs from 'fs';
19import { FileUtils } from '../../src/utils/FileUtils';
20import { FilesMap, Parser } from '../../src/coreImpl/parser/parser';
21import { StringConstant } from '../../src/utils/Constant';
22import { DiffHelper } from '../../src/coreImpl/diff/diff';
23import { BasicDiffInfo } from '../../src/typedef/diff/ApiInfoDiff';
24import { ApiStatisticsHelper } from '../../src/coreImpl/statistics/Statistics';
25import { ApiStatisticsInfo } from '../../src/typedef/statistics/ApiStatistics';
26import { Check } from '../../src/coreImpl/checker/src/api_check_plugin';
27import { apiCheckResult, cleanApiCheckResult, compositiveResult } from '../../src/utils/checkUtils';
28import { LocalEntry } from '../../src/coreImpl/checker/local_entry';
29import { ApiChangeCheck } from '../../src/coreImpl/checker/src/check_api_diff';
30import { ApiResultMessage, checkEntryType } from '../../src/typedef/checker/result_type';
31const utDir: string = 'test/ut';
32const outputDir: string = 'test/output';
33const expectDir: string = 'test/expect';
34
35describe('testParserEachSince', function () {
36  before(() => { Parser.cleanParserParamSDK(); });
37  const testFileDir: string = path.join(FileUtils.getBaseDirName(), utDir, 'parserSince');
38  const outputFileDir: string = path.join(FileUtils.getBaseDirName(), outputDir, 'parserSince');
39  const expectFileDir: string = path.join(FileUtils.getBaseDirName(), expectDir, 'parserSince');
40  const testFileNames: string[] = fs.readdirSync(testFileDir);
41  testFileNames.forEach((testFileName: string) => {
42    const baseName: string = path
43      .basename(testFileName)
44      .replace(/.d.ts/g, '')
45      .replace(/.d.ets/g, '');
46    const testFilePath: string = path.join(testFileDir, testFileName);
47    const outputFilePath: string = path.join(outputFileDir, `${baseName}.json`);
48    const expectFilePath: string = path.join(expectFileDir, `${baseName}.json`);
49    it('\ntestFile#' + testFilePath + '\noutput:' + outputFilePath + '\nexpect:' + expectFilePath, function () {
50      if (fs.existsSync(outputFilePath)) {
51        fs.rmdirSync(outputFilePath, { recursive: true });
52      }
53      if (!fs.existsSync(outputFileDir)) {
54        fs.mkdirSync(outputFileDir);
55      }
56      const outputContent: string = Parser.getParseEachSince(Parser.parseFile(testFileDir, testFilePath));
57      fs.writeFileSync(outputFilePath, outputContent, StringConstant.UTF8);
58      const expectFileContent: string = fs.readFileSync(expectFilePath, 'utf-8').replace(/\r\n/g, '\n');
59      expect(outputContent).eql(expectFileContent);
60    });
61  });
62});
63
64describe('testParser', function () {
65  before(() => { Parser.cleanParserParamSDK(); });
66  const testFileDir: string = path.join(FileUtils.getBaseDirName(), utDir, 'parser');
67  const outputFileDir: string = path.join(FileUtils.getBaseDirName(), outputDir, 'parser');
68  const expectFileDir: string = path.join(FileUtils.getBaseDirName(), expectDir, 'parser');
69  const testFileNames: string[] = fs.readdirSync(testFileDir);
70  testFileNames.forEach((testFileName: string) => {
71    const baseName: string = path
72      .basename(testFileName)
73      .replace(/.d.ts/g, '')
74      .replace(/.d.ets/g, '');
75    const testFilePath: string = path.join(testFileDir, testFileName);
76    const outputFilePath: string = path.join(outputFileDir, `${baseName}.json`);
77    const expectFilePath: string = path.join(expectFileDir, `${baseName}.json`);
78    it('\ntestFile#' + testFilePath + '\noutput:' + outputFilePath + '\nexpect:' + expectFilePath, function () {
79      if (fs.existsSync(outputFilePath)) {
80        fs.rmdirSync(outputFilePath, { recursive: true });
81      }
82      if (!fs.existsSync(outputFileDir)) {
83        fs.mkdirSync(outputFileDir);
84      }
85      const outputContent: string = Parser.getParseResults(Parser.parseFile(testFileDir, testFilePath));
86      fs.writeFileSync(outputFilePath, outputContent, StringConstant.UTF8);
87      const expectFileContent: string = fs.readFileSync(expectFilePath, 'utf-8').replace(/\r\n/g, '\n');
88      expect(outputContent).eql(expectFileContent);
89    });
90  });
91});
92
93describe('testApiDiff', function () {
94  before(() => { Parser.cleanParserParamSDK(); });
95  const testOldFileDir: string = path.join(FileUtils.getBaseDirName(), utDir, 'apiDiff/old');
96  const testNewFileDir: string = testOldFileDir.replace('old', 'new');
97  const outputFileDir: string = path.join(FileUtils.getBaseDirName(), outputDir, 'apiDiff');
98  const expectFileDir: string = path.join(FileUtils.getBaseDirName(), expectDir, 'apiDiff');
99  const testOldFileNames: string[] = fs.readdirSync(testOldFileDir);
100  testOldFileNames.forEach((testOldFileName: string) => {
101    const baseName: string = path
102      .basename(testOldFileName)
103      .replace(/.d.ts/g, '')
104      .replace(/.d.ets/g, '');
105    const testOldFilePath: string = path.join(testOldFileDir, testOldFileName);
106    const testNewFilePath: string = testOldFilePath.replace('old', 'new');
107    const outputFilePath: string = path.join(outputFileDir, `${baseName}.json`);
108    const expectFilePath: string = path.join(expectFileDir, `${baseName}.json`);
109    it('\ntestFile#' + testOldFilePath + '\noutput:' + outputFilePath + '\nexpect:' + expectFilePath, function () {
110      if (fs.existsSync(outputFilePath)) {
111        fs.rmdirSync(outputFilePath, { recursive: true });
112      }
113      if (!fs.existsSync(outputFileDir)) {
114        fs.mkdirSync(outputFileDir);
115      }
116      Parser.cleanParserParamSDK();
117      const oldSDKApiMap: FilesMap = Parser.parseFile(testOldFileDir, testOldFilePath);
118      Parser.cleanParserParamSDK();
119      const newSDKApiMap: FilesMap = Parser.parseFile(testNewFileDir, testNewFilePath);
120      const diffInfos: BasicDiffInfo[] = DiffHelper.diffSDK(oldSDKApiMap, newSDKApiMap, true);
121      const outputContent: string = JSON.stringify(diffInfos, null, 2);
122      fs.writeFileSync(outputFilePath, outputContent, StringConstant.UTF8);
123      const expectFileContent: string = fs.readFileSync(expectFilePath, 'utf-8').replace(/\r\n/g, '\n');
124      expect(outputContent).eql(expectFileContent);
125    });
126  });
127});
128
129describe('testStatistics', function () {
130  before(() => { Parser.cleanParserParamSDK(); });
131  const testFileDir: string = path.join(FileUtils.getBaseDirName(), utDir, 'apiStatistics');
132  const outputFileDir: string = path.join(FileUtils.getBaseDirName(), outputDir, 'apiStatistics');
133  const expectFileDir: string = path.join(FileUtils.getBaseDirName(), expectDir, 'apiStatistics');
134  const testFileNames: string[] = fs.readdirSync(testFileDir);
135  testFileNames.forEach((testFileName: string) => {
136    const baseName: string = path
137      .basename(testFileName)
138      .replace(/.d.ts/g, '')
139      .replace(/.d.ets/g, '');
140    const testFilePath: string = path.join(testFileDir, testFileName);
141    const outputFilePath: string = path.join(outputFileDir, `${baseName}.json`);
142    const expectFilePath: string = path.join(expectFileDir, `${baseName}.json`);
143    it('\ntestFile#' + testFilePath + '\noutput:' + outputFilePath + '\nexpect:' + expectFilePath, function () {
144      if (!fs.existsSync(outputFileDir)) {
145        fs.mkdirSync(outputFileDir);
146      }
147      const apiInfos: ApiStatisticsInfo[] = ApiStatisticsHelper.getApiStatisticsInfos(
148        Parser.parseFile(testFileDir, testFilePath)
149      ).apiStatisticsInfos;
150      const outputContent: string = JSON.stringify(apiInfos, null, 2);
151      fs.writeFileSync(outputFilePath, outputContent, StringConstant.UTF8);
152      const expectFileContent: string = fs.readFileSync(expectFilePath, 'utf-8').replace(/\r\n/g, '\n');
153      expect(outputContent).eql(expectFileContent);
154    });
155  });
156});
157
158describe('testApiCheck', function () {
159  before(() => { Parser.cleanParserParamSDK(); });
160  const testFileDir: string = path.join(FileUtils.getBaseDirName(), utDir, 'apiCheck');
161  const outputFileDir: string = path.join(FileUtils.getBaseDirName(), outputDir, 'apiCheck');
162  const expectFileDir: string = path.join(FileUtils.getBaseDirName(), expectDir, 'apiCheck');
163  const testFileNames: string[] = fs.readdirSync(testFileDir);
164  testFileNames.forEach((testFileName: string) => {
165    const baseName: string = path
166      .basename(testFileName)
167      .replace(/.d.ts/g, '')
168      .replace(/.d.ets/g, '');
169    const testFilePath: string = path.join(testFileDir, testFileName);
170    const outputFilePath: string = path.join(outputFileDir, `${baseName}.json`);
171    const expectFilePath: string = path.join(expectFileDir, `${baseName}.json`);
172    it('\ntestFile#' + testFilePath + '\noutput:' + outputFilePath + '\nexpect:' + expectFilePath, function () {
173      if (!fs.existsSync(outputFileDir)) {
174        fs.mkdirSync(outputFileDir);
175      }
176      Check.scanEntry([testFilePath], '');
177      let ruleName: string = testFileName.substring(0, testFileName.indexOf('.'));
178      ruleName = testFileName.indexOf('API_DEFINE_ANONYMOUS_FUNCTION') !== -1 ?
179        'API_DEFINE_ANONYMOUS_FUNCTION_01' : ruleName;
180      ruleName = testFileName.indexOf('API_DEFINE_HUMP_01_small') !== -1 ?
181        'API_DEFINE_HUMP_01' : ruleName;
182      ruleName = testFileName.indexOf('API_DEFINE_HUMP_02_LARGE') !== -1 ?
183        'API_DEFINE_HUMP_02' : ruleName;
184      ruleName = testFileName.indexOf('API_DEFINE_NAME_02_ability') !== -1 ?
185        'API_DEFINE_NAME_02' : ruleName;
186
187      LocalEntry.maskAlarm(compositiveResult, [ruleName]);
188      apiCheckResult.forEach((result: ApiResultMessage) => {
189        result.buggyFilePath = result.buggyFilePath.substring(result.buggyFilePath.indexOf('build-tools'), result.buggyFilePath.length);
190      });
191      const outputContent: string = JSON.stringify(apiCheckResult, null, 2);
192      fs.writeFileSync(outputFilePath, outputContent, StringConstant.UTF8);
193      const expectFileContent: string = fs.readFileSync(expectFilePath, 'utf-8').replace(/\r\n/g, '\n');
194      expect(outputContent).eql(expectFileContent);
195    });
196  });
197});
198
199describe('testApiChangeCheck', function () {
200  before(() => { Parser.cleanParserParamSDK(); });
201  const testFileDir: string = path.join(FileUtils.getBaseDirName(), utDir, 'apiChange');
202  const outputFileDir: string = path.join(FileUtils.getBaseDirName(), outputDir, 'apiChange');
203  const expectFileDir: string = path.join(FileUtils.getBaseDirName(), expectDir, 'apiChange');
204  const testOldFileDir: string = path.join(FileUtils.getBaseDirName(), utDir, 'apiChange/old');
205  const testOldFileNames: string[] = fs.readdirSync(testOldFileDir);
206
207  ApiChangeCheck.checkApiChange(testFileDir);
208  testOldFileNames.forEach((testOldFileName: string) => {
209    const baseName: string = path
210      .basename(testOldFileName)
211      .replace(/.d.ts/g, '')
212      .replace(/.d.ets/g, '');
213    const testOldFilePath: string = path.join(testOldFileDir, testOldFileName);
214    const outputFilePath: string = path.join(outputFileDir, `${baseName}.json`);
215    const expectFilePath: string = path.join(expectFileDir, `${baseName}.json`);
216    it('\ntestFile#' + testOldFilePath + '\noutput:' + outputFilePath + '\nexpect:' + expectFilePath, function () {
217      if (!fs.existsSync(outputFileDir)) {
218        fs.mkdirSync(outputFileDir);
219      }
220      cleanApiCheckResult();
221      LocalEntry.maskAlarm(compositiveResult, [baseName]);
222      const keyString: string[] = [];
223      const finalResult: ApiResultMessage[] = [];
224      apiCheckResult.forEach(apiCheck => {
225        const key: string = apiCheck.description + apiCheck.mainBuggyCode + apiCheck.extendInfo.hierarchicalRelations;
226        if (!keyString.includes(key)) {
227          keyString.push(key);
228          finalResult.push(apiCheck);
229        }
230      });
231      const outputContent: string = JSON.stringify(finalResult, null, 2);
232      fs.writeFileSync(outputFilePath, outputContent, StringConstant.UTF8);
233      const expectFileContent: string = fs.readFileSync(expectFilePath, 'utf-8').replace(/\r\n/g, '\n');
234      expect(outputContent).eql(expectFileContent);
235    });
236  });
237
238  describe('testApiCheckIncrement', function testApiCheckIncrement() {
239    const testFileDir: string = path.join(FileUtils.getBaseDirName(), '/test/ut/apiIncrement');
240    const outputFileDir: string = path.join(FileUtils.getBaseDirName(), '/test/output/apiIncrement');
241    const expectFileDir: string = path.join(FileUtils.getBaseDirName(), '/test/expect/apiIncrement');
242    const testFileNames: string[] = fs.readdirSync(testFileDir);
243
244    testFileNames.forEach((testFileName: string) => {
245      const testFilePath: string = path.join(testFileDir, testFileName);
246      const testOldFileDir: string = path.join(testFilePath, '/old');
247      const testNewFileDir: string = path.join(testFilePath, '/new');
248      const baseName: string = path
249        .basename(testFileName)
250        .replace(/.d.ts/g, '')
251        .replace(/.d.ets/g, '');
252      const outputFilePath: string = path.join(outputFileDir, `${baseName}.json`);
253      const expectFilePath: string = path.join(expectFileDir, `${baseName}.json`);
254      it('\ntestFile#' + testFilePath + '\noutput:' + outputFilePath + '\nexpect:' + expectFilePath, function () {
255        if (!fs.existsSync(outputFileDir)) {
256          fs.mkdirSync(outputFileDir);
257        }
258        cleanApiCheckResult();
259        const files: Array<string> = FileUtils.readFilesInDir(testNewFileDir);
260        const checkParam: checkEntryType = {
261          filePathArr: files,
262          fileRuleArr: ['all'],
263          output: './result.json',
264          prId: testFilePath,
265          isOutExcel: 'true',
266          isIncrement: true,
267        };
268        LocalEntry.checkEntryLocal(checkParam);
269        const outputContent: string = JSON.stringify(apiCheckResult, null, 2);
270        fs.writeFileSync(outputFilePath, outputContent, StringConstant.UTF8);
271        const expectFileContent: string = fs.readFileSync(expectFilePath, 'utf-8').replace(/\r\n/g, '\n');
272        expect(outputContent).eql(expectFileContent);
273      });
274    });
275  });
276
277