• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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 util = require('util');
17import { replaceAll } from "../common/tool";
18import { FuncInfo, GenInfo, InterfaceList, ParamObj, TypeList } from "./datatype";
19import { getInterfaceBody, getTypeBody, transTskey2Ckey } from './gendts';
20import { testAbilityFuncTemplate } from "../template/func_template";
21import { Logger } from '../common/log';
22import { cpp2DtsKey, dts2TestValue } from '../template/dtscpp/dts2cpp_key';
23import * as path from 'path';
24import * as fs from 'fs';
25import { testFirstGenTemplate } from '../template/dtscpp/dtscpp_testfirstgen_template';
26const INTVALUE = 5;
27const FLOATVALUE = 2.5;
28
29export function generateFuncTestCase(funcInfo: FuncInfo, rawFileName: string,  typeList: TypeList[], interfaceList: InterfaceList[]) {
30  let { funcParamUse, funcParamDefine, funcInfoParams } = genInitTestfunc(funcInfo, typeList, interfaceList);
31  // 去除调用参数的最后一个','
32  let index = funcParamUse.lastIndexOf(', ');
33  funcParamUse = funcParamUse.substring(0, index);
34  let callFunc = '';
35  let hilogContent = '';
36  // 调用函数
37  Logger.getInstance().info("test funcInfo:" + JSON.stringify(funcInfo));
38  if (getJsType(funcInfo.retType) !== 'void') {
39    callFunc = util.format('let result: %s = testNapi.%s(%s)\n    ', getJsType(funcInfo.retType), funcInfo.name, funcParamUse);
40    // 加 hilog 打印
41    hilogContent = util.format('hilog.info(0x0000, "testTag", "Test NAPI %s: ", JSON.stringify(result));\n    ', funcInfo.name);
42    hilogContent += util.format('Logger.getInstance().info("testTag", "Test NAPI %s: ", JSON.stringify(result));\n    ', funcInfo.name);
43  } else {
44    callFunc = util.format('testNapi.%s(%s)\n    ', funcInfo.name, funcParamUse);
45  }
46  let funcTestReplace = funcParamDefine + callFunc + hilogContent;
47  // 替换test_case_name
48  let funcTestContent = replaceAll(testAbilityFuncTemplate, '[func_direct_testCase]', funcTestReplace);
49  funcTestContent = replaceAll(funcTestContent, '[test_case_name]', funcInfo.name);
50  funcTestContent = replaceAll(funcTestContent, '[file_introduce_replace]', rawFileName);
51  funcTestContent = replaceAll(funcTestContent, '[func_introduce_replace]', funcInfo.name);
52  funcTestContent = replaceAll(funcTestContent, '[input_introduce_replace]', funcInfoParams === '' ? 'void' : funcInfoParams);
53  funcTestContent = replaceAll(funcTestContent, '[func_return_replace]', funcInfo.retType);
54
55  return funcTestContent;
56}
57
58export function genInitTestfunc(funcInfo: FuncInfo, typeList: TypeList[], interfaceList: InterfaceList[]) {
59  let funcParamDefine = '';
60  let funcParamUse = '';
61  let funcInfoParams = '';
62  let funcInfoParamTemp = '[paramName]: [paramType]; ';
63  // 判断函数有几个参数,依次给参数赋值
64  for (let i = 0; i < funcInfo.params.length; i++) {
65    let funcInfoParamReplace = replaceAll(funcInfoParamTemp, '[paramName]', funcInfo.params[i].name);
66    funcInfoParamReplace = replaceAll(funcInfoParamReplace, '[paramType]', funcInfo.params[i].type);
67    funcInfoParams += funcInfoParamReplace;
68    let testType = getTestType(funcInfo.params[i].type);
69    if (testType === 'int') {
70      funcParamDefine += util.format('let %s = %s\n    ', funcInfo.params[i].name, INTVALUE);
71      funcParamUse += funcInfo.params[i].name + ', ';
72    } else if (testType === 'float') {
73      funcParamDefine += util.format('let %s = %s\n    ', funcInfo.params[i].name, FLOATVALUE);
74      funcParamUse += funcInfo.params[i].name + ', ';
75    } else if (testType === 'bool') {
76      funcParamDefine += util.format('let %s = %s\n    ', funcInfo.params[i].name, true);
77      funcParamUse += funcInfo.params[i].name + ', ';
78    } else if (testType === 'string') {
79      funcParamDefine += util.format('let %s = "%s"\n    ', funcInfo.params[i].name, 'hello');
80      funcParamUse += funcInfo.params[i].name + ', ';
81    } else if (getTypeBody(testType, typeList)) {
82      let typeDefineRes = getTypeDefine(testType, funcParamDefine, funcInfo, i, funcParamUse, typeList);
83      funcParamDefine = typeDefineRes[0];
84      funcParamUse = typeDefineRes[1];
85    } else if (getInterfaceBody(testType, interfaceList)) {
86      let interfaceDefineRes = getInterfaceDefine(testType, funcParamDefine, funcInfo, i, funcParamUse, interfaceList);
87      funcParamDefine = interfaceDefineRes[0];
88      funcParamUse = interfaceDefineRes[1];
89    }
90  }
91  return { funcParamUse, funcParamDefine, funcInfoParams };
92}
93
94export function getTypeDefine(testType: string, funcParamDefine: string, funcInfo: FuncInfo, i: number, funcParamUse: string, typeList: TypeList[]) {
95  let cTypeDefine = getTypeBody(testType, typeList);
96  let typeDefType = transTskey2Ckey(cTypeDefine as string);
97  // genType
98  if (typeDefType === 'number') {
99    funcParamDefine += util.format('let %s = %s\n    ', funcInfo.params[i].name, INTVALUE);
100    funcParamUse += funcInfo.params[i].name + ', ';
101  } else if (typeDefType === 'string') {
102    funcParamDefine += util.format('let %s = "%s"\n    ', funcInfo.params[i].name, 'hello');
103    funcParamUse += funcInfo.params[i].name + ', ';
104  } else if (typeDefType === 'boolean') {
105    funcParamDefine += util.format('let %s = %s\n    ', funcInfo.params[i].name, false);
106    funcParamUse += funcInfo.params[i].name + ', ';
107  }
108  return [funcParamDefine, funcParamUse];
109}
110
111export function genInterFuncParamStr(param: ParamObj[]) {
112  let paramsStr = '';
113  for(let i = 0; i < param.length; i++) {
114    let rawType = transTskey2Ckey(param[i].type);
115    paramsStr += param[i].name + ': ' + rawType;
116    if (i !== param.length - 1) {
117      paramsStr += ', ';
118    }
119  }
120  return paramsStr;
121}
122
123export function getInterfaceDefine(testType: string, funcParamDefine: string, funcInfo: FuncInfo, i: number, funcParamUse: string, interfaceList: InterfaceList[]) {
124  let objValue = getInterfaceBody(testType, interfaceList);
125  let objTestData = 'let %s:testNapi.%s = { ';
126  let interParams = objValue!.params;
127  let interFuncs = objValue!.funcs;
128  // 成员变量赋值
129  for (let j = 0; j < interParams.length; j++) {
130    let paramType = transTskey2Ckey(interParams[j].type);
131    if (paramType === 'number') {
132      objTestData += util.format('%s: %s, ', interParams[j].name, INTVALUE);
133    } else if (paramType === 'string') {
134      objTestData += util.format('%s: "%s", ', interParams[j].name, 'hello');
135    } else if (paramType === 'boolean') {
136      objTestData += util.format('%s: %s, ', interParams[j].name, true);
137    } else if (getInterfaceBody(paramType, interfaceList)) {
138      objTestData += util.format('%s: null, ', interParams[j].name);
139    }
140  }
141
142  // 成员函数
143  for (let j = 0; j < interFuncs.length; j++) {
144    let paramStr = genInterFuncParamStr(interFuncs[j].parameters);
145    let initInterFunc = util.format('%s:(%s) => ',interFuncs[j].name, paramStr);
146    let interFuncRetType = transTskey2Ckey(interFuncs[j].returns);
147    if (interFuncRetType === 'void') {
148      let interfaceFuncRetDefine = initInterFunc + '{}';
149      objTestData += util.format('%s, ', interfaceFuncRetDefine);
150    } else if (interFuncRetType === 'string') {
151      let interfaceFuncRetDefine = initInterFunc + '{return ""}';
152      objTestData += util.format('%s, ', interfaceFuncRetDefine);
153    } else if (interFuncRetType === 'boolean') {
154      let interfaceFuncRetDefine = initInterFunc + '{ return true }';
155      objTestData += util.format('%s, ', interfaceFuncRetDefine);
156    } else if (interFuncRetType === 'number') {
157      let interfaceFuncRetDefine = initInterFunc + '{ return 0 }';
158      objTestData += util.format('%s, ', interfaceFuncRetDefine);
159    }
160  }
161
162  // 去除调用参数的最后一个','
163  let index = objTestData.lastIndexOf(', ');
164  if (index !== -1) {
165    objTestData = objTestData.substring(0, index) + ' }\n    ';
166  } else {
167    objTestData = 'let %s:testNapi.%s = null;\n    ';
168  }
169  funcParamDefine += util.format(objTestData, funcInfo.params[i].name, testType);
170  funcParamUse += funcInfo.params[i].name + ', ';
171  return [funcParamDefine, funcParamUse];
172}
173
174export function getTestType(type: string) {
175    // 去掉const 和 *
176    type = replaceAll(type,'const', '');
177    type = replaceAll(type, '*', '').trim();
178    if (type === 'uint32_t' || type === 'int32_t' || type === 'int16_t' ||
179        type === 'int64_t' || type === 'int' || type === 'size_t') {
180        return 'int';
181    } else if (type === 'double_t' || type === 'double' || type === 'float') {
182        return 'float';
183    } else if (type === 'bool') {
184        return 'bool';
185    } else if (type === 'std::string' || type.indexOf('char') >= 0) {
186        return 'string';
187    }
188    return type;
189}
190
191export function getJsType(type: string) {
192    type = replaceAll(type,'const', '');
193    type = replaceAll(type, '*', '').trim();
194    for(const keyItem of cpp2DtsKey) {
195      for(const str of keyItem.keys) {
196        if (type.includes(str)) {
197          return transTskey2Ckey(type);
198        }
199      }
200    }
201    return 'testNapi.' + type.replace('*', '').trim();
202}
203
204// ----------------------- gentest ------------------------
205// 用H文件为源文件生成Ability.test.ets文件
206export function genAbilitytestFile(rootInfo: GenInfo, out: string) {
207  if (out === undefined || out === null || out.trim() === '') {
208    out = path.dirname(rootInfo.rawFilePath);
209  }
210  let testContent = ''
211  if (rootInfo.parseObj && rootInfo.parseObj.funcs) {
212    rootInfo.parseObj.funcs.forEach(funcInfo => {
213      let callFunc = ''; // 调用函数内容
214      let hilogContent = ''; // hilog内容
215      let funcParamDefine = ''; // 函数参数定义并初始化
216      let funcParamUse = ''; // 函数参数使用
217      let funcInfoParams = ''; // 注释
218      let funcInfoParamTemp = '[paramName]: [paramType]; ';
219      // 遍历方法参数,给参数赋初始值,生成注释和参数使用内容
220      // 1. 先将所有type转换为ts的type
221      for (let i = 0; i < funcInfo.parameters.length; ++i) {
222        // 注释
223        let funcInfoParamReplace = replaceAll(funcInfoParamTemp, '[paramName]',
224          funcInfo.parameters[i].name);
225        funcInfoParamReplace = replaceAll(funcInfoParamReplace, '[paramType]',
226          funcInfo.parameters[i].type);
227        funcInfoParams += funcInfoParamReplace;
228        // 参数定义并初始化
229        const param = funcInfo.parameters[i];
230        let paramType = transTskey2Ckey(param.type);
231        let testValue = 'undefined; // Please give an any value.';  // any类型咋赋值?
232        dts2TestValue.forEach(item => {
233          if (item.key === paramType) {
234            testValue = item.value;
235          }
236        })
237        funcParamDefine += util.format('let %s: %s = %s;\n    ',
238          funcInfo.parameters[i].name, paramType, testValue);
239        funcParamUse += funcInfo.parameters[i].name + ', ';
240        // 如果是最后一个参数,去掉最后的逗号和空格
241        if (funcInfo.parameters.length === i + 1) {
242          funcParamUse = funcParamUse.slice(0, -2); // 去掉最后一个逗号和空格
243        }
244      }
245      // 返回值,如果本来就是ts类型就不用替换了:如Promise<unknown>,就不用替换了
246      let tsPromiseReg = /Promise<([^>]+)>/g;
247      let returnType = tsPromiseReg.exec(funcInfo.returns)? funcInfo.returns:
248        transTskey2Ckey(funcInfo.returns);
249      if (returnType === 'void') {
250        callFunc = util.format('testNapi.%s(%s)\n    ', funcInfo.name,
251          funcParamUse);
252      } else {
253        callFunc = util.format('let result: %s = testNapi.%s(%s)\n    ',
254          returnType, funcInfo.name, funcParamUse);
255        hilogContent = util.format(
256          'hilog.info(0x0000, "testTag", "Test NAPI %s: ", JSON.stringify(result));\n    ',funcInfo.name);
257      }
258      let funcTestReplace = funcParamDefine + callFunc + hilogContent;
259      let rawFileName = path.basename(rootInfo.rawFilePath);
260      // 替换test_case_name
261      let funcTestContent = replaceAll(testAbilityFuncTemplate,
262        '[func_direct_testCase]', funcTestReplace);
263      funcTestContent = replaceAll(funcTestContent, '[test_case_name]',
264        funcInfo.name);
265      funcTestContent = replaceAll(funcTestContent, '[file_introduce_replace]',
266        rawFileName);
267      funcTestContent = replaceAll(funcTestContent, '[func_introduce_replace]',
268        funcInfo.name);
269      funcTestContent = replaceAll(funcTestContent,
270        '[input_introduce_replace]', funcInfoParams === '' ? 'void' : funcInfoParams);
271      funcTestContent = replaceAll(funcTestContent, '[func_return_replace]',
272        funcInfo.returns);
273      testContent += funcTestContent;
274    });
275
276    let fileContent = replaceAll(testFirstGenTemplate.content,
277      '[testAbilityFunctions]', testContent);
278    // 将文件写入out文件夹
279    if (!fs.existsSync(out)) {
280      fs.mkdirSync(out, { recursive: true });
281    }
282    let lowerFileName = rootInfo.fileName.toLocaleLowerCase();
283    let fileName = testFirstGenTemplate.name.replace('[fileName]',
284      lowerFileName);
285    let filePath = path.join(out, fileName);
286    fs.writeFileSync(filePath, fileContent);
287  }
288}