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