1/* 2 * Copyright (c) 2024 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 ts from 'typescript'; 17import { shouldKeepCurFileParamerters, shouldKeepParameter } from '../../../src/utils/KeepParameterUtils'; 18import { INameObfuscationOption } from '../../../src/configs/INameObfuscationOption'; 19import assert from 'assert'; 20import { MangledSymbolInfo } from '../../../src/common/type'; 21import { TypeUtils } from '../../../src/utils/TypeUtils'; 22import { NodeUtils } from '../../../src/utils/NodeUtils'; 23import { PropCollections } from '../../../src/ArkObfuscator'; 24import { nodeSymbolMap } from '../../../src/utils/ScopeAnalyzer'; 25 26describe('Tester Cases for shouldKeepCurFileParamerters.', function () { 27 it('Tester 1-1: shouldKeepCurFileParamerters returns true', function () { 28 let path = '/user/local/tester.d.ts'; 29 let content = 'export declare let a: number'; 30 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 31 const config: INameObfuscationOption = { 32 'mEnable': true, 33 'mNameGeneratorType': 1, 34 'mDictionaryList': [], 35 'mRenameProperties': false, 36 'mKeepStringProperty': true, 37 'mTopLevel': false, 38 'mKeepParameterNames': true, 39 'mReservedProperties': [] 40 }; 41 const actual = shouldKeepCurFileParamerters(ast, config); 42 assert.strictEqual(actual, true); 43 }); 44 45 it('Tester 1-2: When mKeepParameterNames is disabled, shouldKeepCurFileParamerters returns false', function () { 46 let path = '/user/local/tester.d.ts'; 47 let content = 'export declare let a: number'; 48 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 49 const config: INameObfuscationOption = { 50 'mEnable': true, 51 'mNameGeneratorType': 1, 52 'mDictionaryList': [], 53 'mRenameProperties': false, 54 'mKeepStringProperty': true, 55 'mTopLevel': false, 56 'mKeepParameterNames': false, 57 'mReservedProperties': [] 58 }; 59 const actual = shouldKeepCurFileParamerters(ast, config); 60 assert.strictEqual(actual, false); 61 }); 62 63 it('Tester 1-3: When file is not declaration file, shouldKeepCurFileParamerters returns false', function () { 64 let path = '/user/local/tester.ts'; 65 let content = 'export declare let a: number'; 66 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 67 const config: INameObfuscationOption = { 68 'mEnable': true, 69 'mNameGeneratorType': 1, 70 'mDictionaryList': [], 71 'mRenameProperties': false, 72 'mKeepStringProperty': true, 73 'mTopLevel': false, 74 'mKeepParameterNames': true, 75 'mReservedProperties': [] 76 }; 77 const actual = shouldKeepCurFileParamerters(ast, config); 78 assert.strictEqual(actual, false); 79 }); 80}); 81 82describe('Tester Cases for shouldKeepParameter.', function () { 83 let path = ''; 84 let config: INameObfuscationOption; 85 this.beforeAll(() => { 86 path = '/user/local/tester.d.ts'; 87 config = { 88 'mEnable': true, 89 'mNameGeneratorType': 1, 90 'mDictionaryList': [], 91 'mRenameProperties': false, 92 'mKeepStringProperty': true, 93 'mTopLevel': false, 94 'mKeepParameterNames': true, 95 'mReservedProperties': [] 96 } 97 }); 98 it('Tester 2-1: When node is undefined, shouldKeepParameter returns false', function () { 99 let content = 'export declare let a: number'; 100 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 101 let node: ts.Identifier = undefined; 102 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 103 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 104 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 105 assert.strictEqual(actual, false); 106 }); 107 108 it('Tester 2-2: When node is not parameter, shouldKeepParameter returns false', function () { 109 let content = 'export declare let a: number'; 110 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 111 let node = (ast.statements[0] as ts.VariableStatement).declarationList.declarations[0].name; 112 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 113 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 114 // @ts-ignore 115 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 116 assert.strictEqual(actual, false); 117 }); 118 119 it('Tester 2-3: When node is parameter has no parent node, shouldKeepParameter returns false', function () { 120 let content = 'export declare function foo(para1: number): void'; 121 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 122 const customNode = ts.createParameter(undefined, undefined, 'a'); 123 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 124 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 125 const actual = shouldKeepParameter(customNode, config, mangledSymbolNames, checker); 126 assert.strictEqual(actual, false); 127 }); 128 129 it('Tester 2-4: When node is parameter, shouldKeepParameter returns true', function () { 130 let content = 'export declare function foo(para1: number): void'; 131 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 132 let node = (ast.statements[0] as ts.FunctionDeclaration).parameters[0]; 133 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 134 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 135 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 136 assert.strictEqual(actual, true); 137 }); 138 139 it('Tester 2-5: When node is TypeParameter, shouldKeepParameter returns true', function () { 140 let content = 'export declare function foo<T>(para1: number): void'; 141 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 142 let node = (ast.statements[0] as ts.FunctionDeclaration).typeParameters[0] as ts.TypeParameterDeclaration; 143 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 144 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 145 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 146 assert.strictEqual(actual, true); 147 }); 148 149 it('Tester 2-6: When node is parameter and function name is not kept, shouldKeepParameter returns false', function () { 150 let content = 'export declare function foo<T>(para1: number): void'; 151 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 152 let node: ts.ParameterDeclaration = (ast.statements[0] as ts.FunctionDeclaration).parameters[0]; 153 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 154 const parentNode: ts.FunctionDeclaration = node.parent as ts.FunctionDeclaration; 155 assert.strictEqual(!!parentNode, true); 156 const functionName: ts.Identifier = parentNode.name as ts.Identifier; 157 assert.strictEqual(!!functionName, true); 158 const sym: ts.Symbol = NodeUtils.findSymbolOfIdentifier(checker, functionName, nodeSymbolMap) as ts.Symbol; 159 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 160 mangledSymbolNames.set(sym, { mangledName: 'a', originalNameWithScope: '' }); 161 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 162 assert.strictEqual(actual, false); 163 }); 164 165 it('Tester 2-7: When node is parameter and function name is kept, shouldKeepParameter returns true', function () { 166 let content = 'export declare function foo<T>(para1: number): void'; 167 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 168 let node: ts.ParameterDeclaration = (ast.statements[0] as ts.FunctionDeclaration).parameters[0]; 169 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 170 const parentNode: ts.FunctionDeclaration = node.parent as ts.FunctionDeclaration; 171 assert.strictEqual(!!parentNode, true); 172 const functionName: ts.Identifier = parentNode.name as ts.Identifier; 173 assert.strictEqual(!!functionName, true); 174 const sym: ts.Symbol = NodeUtils.findSymbolOfIdentifier(checker, functionName, nodeSymbolMap) as ts.Symbol; 175 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 176 mangledSymbolNames.set(sym, { mangledName: 'foo', originalNameWithScope: '' }); 177 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 178 assert.strictEqual(actual, true); 179 }); 180 181 it('Tester 2-8: When node is parameter and function name is kept, shouldKeepParameter returns true', function () { 182 let content = 'export declare function foo<T>(para1: number): void'; 183 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 184 let node: ts.ParameterDeclaration = (ast.statements[0] as ts.FunctionDeclaration).parameters[0]; 185 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 186 const parentNode: ts.FunctionDeclaration = node.parent as ts.FunctionDeclaration; 187 assert.strictEqual(!!parentNode, true); 188 const functionName: ts.Identifier = parentNode.name as ts.Identifier; 189 assert.strictEqual(!!functionName, true); 190 const sym: ts.Symbol = NodeUtils.findSymbolOfIdentifier(checker, functionName, nodeSymbolMap) as ts.Symbol; 191 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 192 mangledSymbolNames.set(sym, { mangledName: 'foo', originalNameWithScope: '' }); 193 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 194 assert.strictEqual(actual, true); 195 }); 196 197 it('Tester 2-9: When node is method and property obf is not enabled, shouldKeepParameter returns true', function () { 198 let content = `declare class A { 199 constructor(para1: number); 200 method(para2: number): void; 201 }`; 202 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 203 let method: ts.MethodDeclaration = (ast.statements[0] as ts.ClassDeclaration).members[1] as ts.MethodDeclaration; 204 let node: ts.ParameterDeclaration = method.parameters[0]; 205 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 206 const methodName: ts.Identifier = method.name as ts.Identifier; 207 assert.strictEqual(!!methodName, true); 208 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 209 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 210 assert.strictEqual(actual, true); 211 }); 212 213 it('Tester 2-10: When node is method and method name is not kept, shouldKeepParameter returns false', function () { 214 let content = `declare class A { 215 constructor(para1: number); 216 method(para2: number): void; 217 }`; 218 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 219 let method: ts.MethodDeclaration = (ast.statements[0] as ts.ClassDeclaration).members[1] as ts.MethodDeclaration; 220 let node: ts.ParameterDeclaration = method.parameters[0]; 221 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 222 const methodName: ts.Identifier = method.name as ts.Identifier; 223 assert.strictEqual(!!methodName, true); 224 const customConfig: INameObfuscationOption = JSON.parse(JSON.stringify(config)); 225 // @ts-ignore 226 customConfig['mRenameProperties'] = true; 227 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 228 const actual = shouldKeepParameter(node, customConfig, mangledSymbolNames, checker); 229 assert.strictEqual(actual, false); 230 }); 231 232 it('Tester 2-11: When node is method and method name is kept, shouldKeepParameter returns true', function () { 233 let content = `declare class A { 234 constructor(para1: number); 235 method(para2: number): void; 236 }`; 237 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 238 let method: ts.MethodDeclaration = (ast.statements[0] as ts.ClassDeclaration).members[1] as ts.MethodDeclaration; 239 let node: ts.ParameterDeclaration = method.parameters[0]; 240 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 241 const methodName: ts.Identifier = method.name as ts.Identifier; 242 assert.strictEqual(!!methodName, true); 243 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 244 PropCollections.reservedProperties.add('method'); 245 const customConfig: INameObfuscationOption = JSON.parse(JSON.stringify(config)); 246 // @ts-ignore 247 customConfig['mRenameProperties'] = true; 248 const actual = shouldKeepParameter(node, customConfig, mangledSymbolNames, checker); 249 assert.strictEqual(actual, true); 250 }); 251 252 it('Tester 2-12: When node is constructor and class name is not kept, shouldKeepParameter returns false', function () { 253 let content = `declare class A { 254 constructor(para1: number); 255 method(para2: number): void; 256 }`; 257 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 258 let construcotr: ts.ConstructorDeclaration = (ast.statements[0] as ts.ClassDeclaration).members[0] as ts.ConstructorDeclaration; 259 let node: ts.ParameterDeclaration = construcotr.parameters[0]; 260 assert.strictEqual(!!node, true); 261 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 262 const className: ts.Identifier = construcotr.parent.name as ts.Identifier; 263 assert.strictEqual(!!className, true); 264 const sym: ts.Symbol = NodeUtils.findSymbolOfIdentifier(checker, className, nodeSymbolMap) as ts.Symbol; 265 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 266 mangledSymbolNames.set(sym, { mangledName: 'a', originalNameWithScope: '' }); 267 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 268 assert.strictEqual(actual, false); 269 }); 270 271 it('Tester 2-13: When node is constructor and class name is kept, shouldKeepParameter returns true', function () { 272 let content = `declare class A { 273 constructor(para1: number); 274 method(para2: number): void; 275 }`; 276 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 277 let construcotr: ts.ConstructorDeclaration = (ast.statements[0] as ts.ClassDeclaration).members[0] as ts.ConstructorDeclaration; 278 const className: ts.Identifier = construcotr.parent.name as ts.Identifier; 279 assert.strictEqual(!!className, true); 280 let node: ts.ParameterDeclaration = construcotr.parameters[0]; 281 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 282 const sym: ts.Symbol = NodeUtils.findSymbolOfIdentifier(checker, className, nodeSymbolMap) as ts.Symbol; 283 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 284 mangledSymbolNames.set(sym, { mangledName: 'A', originalNameWithScope: '' }); 285 const actual = shouldKeepParameter(node, config, mangledSymbolNames, checker); 286 assert.strictEqual(actual, true); 287 }); 288 289 it('Tester 2-14: When node is MethodSignature, shouldKeepParameter returns false', function () { 290 let content = 'export declare function foo(para1: number): void'; 291 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 292 const customIdentifier = ts.createIdentifier('a1'); 293 const customParaNode = ts.createParameter(undefined, undefined, customIdentifier); 294 // @ts-ignore 295 customIdentifier.parent = customParaNode; 296 const customMethodSig = ts.createMethodSignature(undefined, [customParaNode], undefined, '', undefined); 297 // @ts-ignore 298 customParaNode.parent = customMethodSig; 299 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 300 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 301 const actual = shouldKeepParameter(customParaNode, config, mangledSymbolNames, checker); 302 assert.strictEqual(actual, false); 303 }); 304 305 it('Tester 2-15: When node is method and name is stringType, shouldKeepParameter returns true', function () { 306 let content = `declare class A { 307 constructor(para1: number); 308 ['strProp'](para2: number): void; 309 }`; 310 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, true); 311 let method: ts.MethodDeclaration = (ast.statements[0] as ts.ClassDeclaration).members[1] as ts.MethodDeclaration; 312 let node: ts.ParameterDeclaration = method.parameters[0]; 313 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 314 const methodName: ts.Identifier = method.name as ts.Identifier; 315 assert.strictEqual(!!methodName, true); 316 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 317 PropCollections.reservedProperties.add('strProp'); 318 const customConfig: INameObfuscationOption = JSON.parse(JSON.stringify(config)); 319 // @ts-ignore 320 customConfig['mRenameProperties'] = true; 321 const actual = shouldKeepParameter(node, customConfig, mangledSymbolNames, checker); 322 assert.strictEqual(actual, true); 323 }); 324 325 it('Tester 2-16: When node is method and the type is unexpected, shouldKeepParameter returns true', function () { 326 let content = `declare class A { 327 constructor(para1: number); 328 ['strProp' + 'prop'](para2: number): void; 329 }`; 330 const ast = ts.createSourceFile(path, content, ts.ScriptTarget.ES2015, false); 331 let method: ts.MethodDeclaration = (ast.statements[0] as ts.ClassDeclaration).members[1] as ts.MethodDeclaration; 332 let node: ts.ParameterDeclaration = method.parameters[0]; 333 const checker: ts.TypeChecker = TypeUtils.createChecker(ast); 334 const methodName: ts.Identifier = method.name as ts.Identifier; 335 assert.strictEqual(!!methodName, true); 336 let mangledSymbolNames: Map<ts.Symbol, MangledSymbolInfo> = new Map<ts.Symbol, MangledSymbolInfo>(); 337 PropCollections.reservedProperties.add('strProp'); 338 const customConfig: INameObfuscationOption = JSON.parse(JSON.stringify(config)); 339 // @ts-ignore 340 customConfig['mRenameProperties'] = true; 341 const actual = shouldKeepParameter(node, customConfig, mangledSymbolNames, checker); 342 assert.strictEqual(actual, false); 343 }); 344}); 345