• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (c) 2022 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// 生成BUILD.gn
16// 生成tool_utility.h,生成tool_utility.cpp
17const { replaceAll } = require('./tools/tool');
18const { writeFile } = require('./tools/FileRW');
19const re = require('./tools/re');
20
21const { jsonCfgList } = require('./tools/common');
22const os = require('os');
23const path = require('path');
24const { NapiLog } = require('./tools/NapiLog');
25
26const DIRECT = 1;
27const SYNC = 2;
28const ASYNC = 4;
29const PROMISE = 8;
30const MAXINT = 100;
31const SUBSTREND = 11;
32const LENGTH = 5;
33const MODTWO = 2;
34let fs = require('fs');
35
36let indexEtsTemplete = `\
37import napitest from '@ohos.[import_module_name]';
38import hilog from '@ohos.hilog';
39
40@Entry
41@Component
42struct Index {
43  @State message: string = 'Hello NAPI Sample';
44
45  build() {
46    Row() {
47      Column() {
48        Text(this.message)
49          .fontSize(50)
50          .fontWeight(FontWeight.Bold)
51        [test_interface_button]
52      }
53      .width('100%')
54    }
55    .height('100%')
56  }
57}
58`;
59let buttonTemplate = `
60Button() {
61    Text('[button_test_interface_name]')
62      .fontSize(20)
63      .fontWeight(FontWeight.Bold)
64  }
65  .type(ButtonType.Capsule)
66  .margin({
67    top: 10
68  })
69  .backgroundColor('#0D9FFB')
70  .width('90%')
71  .height('5%')
72  .onClick(() => {
73    hilog.info(0x0000, 'testTag', 'button onClick!');
74
75    [button_test_interface_code]
76
77    hilog.info(0x0000, 'testTag', 'button onClick end !');
78  });
79`;
80
81let FuncCfgList = [];
82function analyzeJsonCfg(jsonCfg) {
83    let len = jsonCfg.length;
84
85    // 将json文件的数据存入jsonCfgList中,目前只配一个
86    for (let i = 0; i < len; i++) {
87      FuncCfgList.push({
88          classOrInterfName: jsonCfg[i].classOrInterfName,
89          functionName: jsonCfg[i].functionName,
90        });
91    }
92}
93
94// 随机生成字符串
95function generateRandomString(length) {
96  let result = '';
97  let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
98  let charactersLength = characters.length;
99
100  for (let i = 0; i < length; i++) {
101    result += characters.charAt(Math.floor(Math.random() * charactersLength));
102  }
103
104  return result;
105}
106
107// 随机生成整数
108function generateRandomInteger(min, max) {
109  min = Math.ceil(min);
110  max = Math.floor(max);
111  return Math.floor(Math.random() * (max - min + 1)) + min;
112}
113
114// 生成index.ets文件中测试接口相关的ETS代码
115function genIndexETSCode(indexEts, testFuncName, funcInfo, className = null) {
116    // 判断接口函数是否是要测试的接口函数
117    if (testFuncName === funcInfo.name) {
118      let funcType = funcInfo.type;
119      let funcValue = funcInfo.value;
120      let retValue = funcInfo.ret;
121
122      // index.ets文件中测试接口button代码生成
123      if (funcType === DIRECT) {
124        indexEts = callDirectFunction(testFuncName, funcValue, retValue, indexEts, className);
125      } else if (funcType === SYNC) {
126        NapiLog.logInfo('SYNC type of function is not supported!');
127      } else if (funcType === ASYNC) {
128        NapiLog.logInfo('ASYNC type of function is not supported!');
129      } else if (funcType === PROMISE) {
130        NapiLog.logInfo('PROMISE type of function is not supported!');
131      } else {
132        NapiLog.logInfo('This type of function(%s) is not supported!'.format(funcType));
133      }
134    } else {
135      NapiLog.logInfo('test function(%s) is not current function(%s)!'.format(testFuncName, funcInfo.name));
136    }
137  return indexEts;
138}
139
140function generateAppCode(structOfTs, destDir, moduleName, jsonCfg) {
141    let ns0 = structOfTs.declareNamespace[0];
142    let license = structOfTs.declareLicense[0];
143    if (ns0 === undefined) {
144        NapiLog.logError('generateAll error:get namespace fail!');
145        return;
146    }
147
148    // 分析配置测试接口的Json文件
149    if (jsonCfg) {
150        analyzeJsonCfg(jsonCfg);
151    }
152
153    // 从文件分析的数据中拿到接口名,接口参数类型与个数,读取出来以此给接口参数赋初值。
154    // 当前只支持一个接口的测试代码生成
155    let indexEts = '';
156    // 测试interface中的方法
157    for (let i in ns0.body.interface) {
158        let ii = ns0.body.interface[i];
159        indexEts = genInterClassFunc(ii, indexEts, FuncCfgList[0].classOrInterfName, FuncCfgList[0].functionName);
160    }
161
162    // 测试class中的方法
163    for (let i in ns0.body.class) {
164        let ii = ns0.body.class[i];
165        indexEts = genInterClassFunc(ii, indexEts, FuncCfgList[0].classOrInterfName, FuncCfgList[0].functionName);
166    }
167
168    // 测试namespace域中的方法
169    for (let i in ns0.body.function) {
170        let ii = ns0.body.function[i];
171        indexEts = genIndexETSCode(indexEts, FuncCfgList[0].functionName, ii);
172    }
173
174    // index.ets文件生成
175    indexEts = replaceAll(indexEts, '[import_module_name]', moduleName);
176    writeFile(re.pathJoin(destDir, 'Index.ets'), null !== license && undefined !== license ? (license + '\n' + indexEts) : indexEts);
177}
178
179// 遍历 interface/class 中的function,生成对interface/class中的接口测试的代码
180function genInterClassFunc(ii, indexEts, testClass = null, testFunc) {
181  let className = ii.name;
182  let interfaceBody = ii.body;
183
184  if (testClass !== className) {
185    NapiLog.logInfo('test class(%s) is not current class(%s)!'.format(testClass, className));
186    return indexEts;
187  }
188  // 遍历interface中的成员方法
189  for (let j = 0; j < interfaceBody.function.length; j++) {
190    // index.ets文件中测试接口button代码生成
191    indexEts = genIndexETSCode(indexEts, testFunc, interfaceBody.function[j], className);
192  }
193  return indexEts;
194}
195
196// 调用direct方法
197function callDirectFunction(funcName, funcValue, retValue, indexEts, className = null) {
198  let testInterfaceName = funcName;
199  let testInterfaceButton = replaceAll(buttonTemplate, '[button_test_interface_name]', testInterfaceName);
200  let testInterfaceValue = ''; // 给方法参数赋初值
201  let funcParamValue = ''; // 调用方法参数
202  // 给接口参数赋初值
203  for (let j in funcValue) {
204    if (funcValue[j].type === 'string') {
205      testInterfaceValue += 'let %s: string = "%s";\n'.format(funcValue[j].name, generateRandomString(LENGTH));
206      funcParamValue += funcValue[j].name + ', ';
207    } else if (funcValue[j].type === 'boolean') {
208      let randomBool = false;
209      if (generateRandomInteger(0, LENGTH) % MODTWO === 0) {
210        randomBool = true;
211      }
212      testInterfaceValue += 'let %s: boolean = %s;\n'.format(funcValue[j].name, randomBool);
213      funcParamValue += funcValue[j].name + ', ';
214    } else if (funcValue[j].type.substring(0, SUBSTREND) === 'NUMBER_TYPE') {
215      testInterfaceValue += 'let %s: number = %s;\n'.format(funcValue[j].name, generateRandomInteger(0, MAXINT));
216      funcParamValue += funcValue[j].name + ', ';
217    } else {
218      console.error('The current parameter type is not supported.');
219    }
220  }
221  funcParamValue = funcParamValue.substring(0, funcParamValue.lastIndexOf(','));
222  // 返回值的处理
223  let useFunction = '';
224  if (retValue === 'void') {
225    useFunction = '%s.%s(%s);'.format(className === null ? 'napitest' : className + 'Obj', funcName, funcParamValue);
226  } else if (retValue === 'string') {
227    useFunction = 'let strRet: string = %s.%s(%s);\n'.format(className === null ? 'napitest' : className + 'Obj', funcName, funcParamValue);
228    useFunction += 'hilog.info(0x0000, "testTag", "%s.%s ret: " + strRet);'.format(className === null ? 'napitest' : className + 'Obj', funcName);
229  } else if (retValue === 'boolean') {
230    useFunction = 'let boolRet: boolean = %s.%s(%s);\n'.format(className === null ? 'napitest' : className + 'Obj', funcName, funcParamValue);
231    useFunction += 'hilog.info(0x0000, "testTag", "%s.%s ret: " + boolRet);'.format(className === null ? 'napitest' : className + 'Obj', funcName);
232  } else if (retValue.substring(0, SUBSTREND) === 'NUMBER_TYPE') {
233    useFunction = 'let numRet: number = %s.%s(%s);\n'.format(className === null ? 'napitest' : className + 'Obj', funcName, funcParamValue);
234    useFunction += 'hilog.info(0x0000, "testTag", "%s.%s ret: " + numRet);'.format(className === null ? 'napitest' : className + 'Obj', funcName);
235  } else {
236    console.error('The current return type is not supported.');
237  }
238  let useInterface = '';
239  if (className !== null) {
240    useInterface = 'let %sObj: napitest.%s = new napitest.%s();\n'.format(className, className, className);
241  }
242  let buttonTestInterface = `%s%s%s`.format(useInterface, testInterfaceValue, useFunction);
243  testInterfaceButton = replaceAll(testInterfaceButton, '[button_test_interface_code]', buttonTestInterface);
244  indexEts = replaceAll(indexEtsTemplete, '[test_interface_button]', testInterfaceButton);
245  return indexEts;
246}
247
248module.exports = {
249    generateAppCode,
250};
251