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 { before } from 'mocha'; 17import { assert } from 'chai'; 18import ts from 'typescript'; 19import { 20 collectExistNames, 21 isInLocalWhitelist, 22 isInPropertyWhitelist, 23 isInTopLevelWhitelist, 24 isMatchWildcard, 25 recordHistoryUnobfuscatedNames, 26 separateUniversalReservedItem, 27 wildcardTransformer 28} from '../../../src/utils/TransformUtil'; 29import type { ReservedNameInfo } from '../../../src/utils/TransformUtil'; 30import { 31 LocalVariableCollections, 32 PropCollections, 33 UnobfuscationCollections 34} from '../../../src/utils/CommonCollections'; 35import secharmony from '../../../src/transformers/rename/RenameIdentifierTransformer'; 36 37describe('test for TransformUtil', function () { 38 let sourceFile: ts.SourceFile; 39 40 before('init ast for source file', function () { 41 const fileContent = ` 42 class Demo{ 43 constructor(public title: string, public content: string, public mark: number) { 44 this.title = title 45 this.content = content 46 this.mark = mark 47 } 48 } 49 `; 50 51 sourceFile = ts.createSourceFile('demo.js', fileContent, ts.ScriptTarget.ES2015, true); 52 }); 53 54 describe('test for function collectExistNames', function () { 55 it('test collectExistNames', function () { 56 const nameSets = collectExistNames(sourceFile); 57 const targetNames = ['Demo', 'title', 'content', 'mark']; 58 59 assert.strictEqual(nameSets.size, targetNames.length); 60 targetNames.forEach((value) => { 61 assert.isTrue(nameSets.has(value)); 62 }); 63 }); 64 }); 65 66 describe('test for function wildcardTransformer', function () { 67 it('test wildcardTransformer', function () { 68 // special characters: '\', '^', '$', '.', '+', '|', '[', ']', '{', '}', '(', ')' 69 const reserved1 = 'a\\+b*'; 70 const reserved2 = '{*}[*](*)'; 71 const reserved3 = '*^'; 72 const reserved4 = '?$\\..'; 73 const reserved5 = '?|123'; 74 75 const result1 = wildcardTransformer(reserved1); 76 const result2 = wildcardTransformer(reserved2); 77 const result3 = wildcardTransformer(reserved3); 78 const result4 = wildcardTransformer(reserved4); 79 const result5 = wildcardTransformer(reserved5); 80 81 assert.strictEqual(result1, String.raw`a\\\+b.*`); 82 assert.strictEqual(result2, String.raw`\{.*\}\[.*\]\(.*\)`); 83 assert.strictEqual(result3, String.raw`.*\^`); 84 assert.strictEqual(result4, String.raw`.\$\\\.\.`); 85 assert.strictEqual(result5, String.raw`.\|123`); 86 }); 87 }); 88 89 describe('test for function separateUniversalReservedItem', function () { 90 it('should throw errors because originalArray is undefined', function () { 91 assert.throws(() => { 92 separateUniversalReservedItem(undefined, false); 93 }, Error, 'Unable to handle the empty array.'); 94 }); 95 96 it('should return reservedInfo because originalArray is defined', function () { 97 let originalArray: string[] = ['*', '?', 'originalArray']; 98 let reservedInfo: ReservedNameInfo = separateUniversalReservedItem(originalArray, true); 99 100 assert.deepStrictEqual(reservedInfo.universalReservedArray, [/^.*$/, /^.$/]); 101 assert.deepStrictEqual(reservedInfo.specificReservedArray, ['originalArray']); 102 103 UnobfuscationCollections.clear(); 104 }); 105 }); 106 107 describe('test for function isMatchWildcard', function () { 108 it('The item can match wildcard characters', function () { 109 let result: boolean = isMatchWildcard([/foo/, /bar/, /baz/], 'foobar'); 110 assert.isTrue(result); 111 }); 112 113 it('The item can not match wildcard characters', function () { 114 let result: boolean = isMatchWildcard([/foo/, /bar/, /baz/], 'abc'); 115 assert.isFalse(result); 116 }); 117 }); 118 119 describe('test for function isInTopLevelWhitelist', function () { 120 const recordMap: Map<string, Set<string>> = new Map(); 121 const nameWithScope:string = 'nameWithScope'; 122 123 describe('printKeptName is true', function () { 124 it('isInTopLevelWhitelist returns false', function() { 125 const originalName: string = 'isInTopLevelWhitelist'; 126 127 const needToRecordProperty: boolean = isInTopLevelWhitelist(originalName, recordMap, nameWithScope, true, true); 128 assert.isFalse(needToRecordProperty); 129 130 PropCollections.clearPropsCollections(); 131 UnobfuscationCollections.clear(); 132 }); 133 134 it('isInTopLevelWhitelist returns true', function() { 135 const originalName1: string = '__global'; 136 const originalName2: string = 'abc'; 137 UnobfuscationCollections.reservedSdkApiForGlobal.add('abc'); 138 UnobfuscationCollections.reservedExportName.add('abc'); 139 PropCollections.reservedProperties.add('abc'); 140 141 const reservedFlag1: boolean = isInTopLevelWhitelist(originalName1, recordMap, nameWithScope, false, true); 142 const reservedFlag2: boolean = isInTopLevelWhitelist(originalName2, recordMap, nameWithScope, false, true); 143 assert.isTrue(reservedFlag1); 144 assert.isTrue(reservedFlag2); 145 146 PropCollections.clearPropsCollections(); 147 UnobfuscationCollections.clear(); 148 }); 149 }); 150 151 describe('printKeptName is false', function () { 152 it('isInTopLevelWhitelist returns false', function () { 153 const originalName: string = 'isInTopLevelWhitelist'; 154 const isReservedTopLevel: boolean = isInTopLevelWhitelist(originalName, recordMap, nameWithScope, true, false); 155 assert.isFalse(isReservedTopLevel); 156 157 PropCollections.clearPropsCollections(); 158 UnobfuscationCollections.clear(); 159 }); 160 161 it('isInTopLevelWhitelist returns true', function () { 162 const originalName: string = '__global'; 163 const isReservedTopLevel: boolean = isInTopLevelWhitelist(originalName, recordMap, nameWithScope, false, false); 164 assert.isTrue(isReservedTopLevel); 165 166 PropCollections.clearPropsCollections(); 167 UnobfuscationCollections.clear(); 168 }); 169 }); 170 }); 171 172 describe('test for function isInPropertyWhitelist', function () { 173 const originalName: string = 'isInPropertyWhitelist'; 174 const recordMap: Map<string, Set<string>> = new Map(); 175 176 it('printKeptName is true', function () { 177 UnobfuscationCollections.reservedSdkApiForProp.add('isInPropertyWhitelist'); 178 UnobfuscationCollections.reservedLangForProperty.add('isInPropertyWhitelist'); 179 UnobfuscationCollections.reservedStruct.add('isInPropertyWhitelist'); 180 UnobfuscationCollections.reservedExportNameAndProp.add('isInPropertyWhitelist'); 181 UnobfuscationCollections.reservedStrProp.add('isInPropertyWhitelist'); 182 UnobfuscationCollections.reservedEnum.add('isInPropertyWhitelist'); 183 PropCollections.reservedProperties.add('isInPropertyWhitelist'); 184 185 const needToRecordProperty: boolean = isInPropertyWhitelist(originalName, recordMap, true); 186 assert.isTrue(needToRecordProperty); 187 188 PropCollections.clearPropsCollections(); 189 UnobfuscationCollections.clear(); 190 }); 191 192 it('printKeptName is false', function () { 193 const isReservedProperty: boolean = isInPropertyWhitelist(originalName, recordMap, false); 194 assert.isFalse(isReservedProperty); 195 UnobfuscationCollections.clear(); 196 }); 197 }); 198 199 describe('test for function isInLocalWhitelist', function () { 200 it('printKeptName is true', function () { 201 const originalName: string = 'isInLocalWhitelist'; 202 const recordMap: Map<string, Set<string>> = new Map(); 203 const nameWithScope: string = '246810'; 204 LocalVariableCollections.reservedLangForLocal.add('isInLocalWhitelist'); 205 UnobfuscationCollections.reservedSdkApiForLocal.add('isInLocalWhitelist'); 206 UnobfuscationCollections.reservedExportName.add('isInLocalWhitelist'); 207 LocalVariableCollections.reservedConfig.add('isInLocalWhitelist'); 208 209 const reservedFlag: boolean = isInLocalWhitelist(originalName, recordMap, nameWithScope, true); 210 assert.isTrue(reservedFlag); 211 212 LocalVariableCollections.clear(); 213 UnobfuscationCollections.clear(); 214 }); 215 216 it('printKeptName is false', function () { 217 const originalName: string = 'originalName'; 218 const recordMap: Map<string, Set<string>> = new Map(); 219 const nameWithScope: string = '12345'; 220 221 const isReservedLocalVariable: boolean = isInLocalWhitelist(originalName, recordMap, nameWithScope,false); 222 assert.isFalse(isReservedLocalVariable); 223 UnobfuscationCollections.clear(); 224 }); 225 226 it('The local variables whitelist should be the same when printKeptName is enabled and disabled', function () { 227 const recordMap: Map<string, Set<string>> = new Map(); 228 const nameWithScope: string = '246810'; 229 LocalVariableCollections.reservedLangForLocal.add('isInLocalWhitelist1'); 230 UnobfuscationCollections.reservedSdkApiForLocal.add('isInLocalWhitelist2'); 231 UnobfuscationCollections.reservedExportName.add('isInLocalWhitelist3'); 232 LocalVariableCollections.reservedConfig.add('isInLocalWhitelist4'); 233 UnobfuscationCollections.reservedSdkApiForProp.add('notInLocalWhitelist'); 234 235 const reservedFlag1: boolean = isInLocalWhitelist('isInLocalWhitelist1', recordMap, nameWithScope, true); 236 const reservedFlag2: boolean = isInLocalWhitelist('isInLocalWhitelist2', recordMap, nameWithScope, true); 237 const reservedFlag3: boolean = isInLocalWhitelist('isInLocalWhitelist3', recordMap, nameWithScope, true); 238 const reservedFlag4: boolean = isInLocalWhitelist('isInLocalWhitelist4', recordMap, nameWithScope, true); 239 const reservedFlag5: boolean = isInLocalWhitelist('notInLocalWhitelist', recordMap, nameWithScope, true); 240 assert.isTrue(reservedFlag1); 241 assert.isTrue(reservedFlag2); 242 assert.isTrue(reservedFlag3); 243 assert.isTrue(reservedFlag4); 244 assert.isFalse(reservedFlag5); 245 246 const isReservedLocalVariable1: boolean = isInLocalWhitelist('isInLocalWhitelist1', recordMap, nameWithScope, false); 247 const isReservedLocalVariable2: boolean = isInLocalWhitelist('isInLocalWhitelist2', recordMap, nameWithScope, false); 248 const isReservedLocalVariable3: boolean = isInLocalWhitelist('isInLocalWhitelist3', recordMap, nameWithScope, false); 249 const isReservedLocalVariable4: boolean = isInLocalWhitelist('isInLocalWhitelist4', recordMap, nameWithScope, false); 250 const isReservedLocalVariable5: boolean = isInLocalWhitelist('notInLocalWhitelist', recordMap, nameWithScope, false); 251 assert.isTrue(isReservedLocalVariable1); 252 assert.isTrue(isReservedLocalVariable2); 253 assert.isTrue(isReservedLocalVariable3); 254 assert.isTrue(isReservedLocalVariable4); 255 assert.isFalse(isReservedLocalVariable5); 256 LocalVariableCollections.clear(); 257 UnobfuscationCollections.clear(); 258 }); 259 }); 260 261 describe('test for function recordHistoryUnobfuscatedNames', function () { 262 const nameWithScope: string = 'abc'; 263 264 it('historyUnobfuscatedNamesMap?.has(nameWithScope) is false', function () { 265 recordHistoryUnobfuscatedNames(nameWithScope); 266 assert.isFalse(UnobfuscationCollections.unobfuscatedNamesMap.has('abc')); 267 }); 268 269 it('historyUnobfuscatedNamesMap?.has(nameWithScope) is true', function () { 270 secharmony.historyUnobfuscatedNamesMap = new Map<string, string[]>(); 271 secharmony.historyUnobfuscatedNamesMap.set('abc', ['bcd', 'efg']); 272 recordHistoryUnobfuscatedNames(nameWithScope); 273 assert.isTrue(UnobfuscationCollections.unobfuscatedNamesMap.has('abc')); 274 UnobfuscationCollections.clear(); 275 secharmony.clearCaches(); 276 }); 277 }); 278});