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 { 17 isViewPUBasedClass, 18 getElementAccessExpressionProperties, 19 getIndexedAccessTypeProperties, 20 stringPropsSet, 21 structPropsSet, 22 getTypeAliasProperties, 23 getInterfaceProperties, 24 getClassProperties, 25 getEnumProperties, 26 getObjectProperties, 27 getViewPUClassProperties 28} from '../../../src/utils/OhsUtil'; 29import { 30 UnobfuscationCollections 31} from '../../../src/utils/CommonCollections'; 32import { describe, it } from 'mocha'; 33import { expect } from 'chai'; 34import * as ts from 'typescript'; 35import { 36 projectWhiteListManager, 37 initProjectWhiteListManager, 38 clearProjectWhiteListManager 39} from '../../../src/utils/ProjectCollections'; 40 41describe('unit test for OhsUtil.ts', function () { 42 describe('test for isViewPUBasedClass function', function () { 43 it('should return false if classNode is an empty object', () => { 44 const classNode = {} as any; 45 expect(isViewPUBasedClass(classNode)).to.be.false; 46 }); 47 48 it('should return false if heritageClauses is undefined', () => { 49 const classNode = ts.factory.createClassDeclaration(undefined, "Class", undefined, undefined, []); 50 expect(isViewPUBasedClass(classNode)).to.be.false; 51 }); 52 53 it('should return false if classNode is undefined', () => { 54 expect(isViewPUBasedClass(undefined)).to.be.false; 55 }); 56 57 it('should return false if heritageClause.types is undefined', () => { 58 const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, undefined); 59 const classNode = ts.factory.createClassDeclaration(undefined, "Class", undefined, [heritageClause], []); 60 expect(isViewPUBasedClass(classNode)).to.be.false; 61 }); 62 63 it('should return false if classNode.heritageClause.types.member is undefined', () => { 64 const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [undefined]); 65 const classNode = ts.factory.createClassDeclaration(undefined, "Class", undefined, [heritageClause], []); 66 expect(isViewPUBasedClass(classNode)).to.be.false; 67 }) 68 69 it('should return true if classNode is set', () => { 70 const typeArguments = [ 71 ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), 72 ]; 73 const type = ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('ViewPU'), typeArguments); 74 const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [type]); 75 const classNode = ts.factory.createClassDeclaration(undefined, "Class", undefined, [heritageClause], []); 76 expect(isViewPUBasedClass(classNode)).to.be.true; 77 }); 78 }) 79 80 describe('test for getTypeAliasProperties function', function () { 81 it('should not add items to propertySet if type is undefined', () => { 82 const name = ts.factory.createIdentifier('MyType'); 83 const typeAliasNode = ts.factory.createTypeAliasDeclaration(undefined, name, undefined, undefined); 84 const propertySet = new Set<string>(); 85 getTypeAliasProperties(typeAliasNode, propertySet); 86 expect(stringPropsSet.size == 0).to.be.true; 87 }); 88 89 it('should add to propertySet if member.name is set', () => { 90 const name = ts.factory.createIdentifier('MyType'); 91 const type = ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword); 92 const identifierName = ts.factory.createIdentifier('Identifier'); 93 const stringName = ts.factory.createStringLiteral('String'); 94 const computedPropertyName = ts.factory.createComputedPropertyName(ts.factory.createStringLiteral('3 + 2')); 95 const types = ts.factory.createTypeLiteralNode([ 96 ts.factory.createPropertySignature(undefined, undefined, undefined, type), 97 ts.factory.createPropertySignature(undefined, identifierName, undefined, type), 98 ts.factory.createPropertySignature(undefined, stringName, undefined, type), 99 ts.factory.createPropertySignature(undefined, computedPropertyName, undefined, type), 100 ]); 101 const typeAliasNode = ts.factory.createTypeAliasDeclaration(undefined, name, undefined, types); 102 const propertySet = new Set<string>(); 103 getTypeAliasProperties(typeAliasNode, propertySet); 104 expect(propertySet.has('Identifier') && propertySet.has('String') && propertySet.has('3 + 2')).to.be.true; 105 expect(stringPropsSet.has('String') && propertySet.has('3 + 2')).to.be.true; 106 }); 107 }) 108 109 describe('test for getElementAccessExpressionProperties function', function () { 110 it('should not add items to propertySet if elementAccessExpression is undefined', () => { 111 const propertySet = new Set<string>(); 112 getElementAccessExpressionProperties(undefined); 113 expect(stringPropsSet.has('value')).to.be.false; 114 }); 115 116 it('should add to propertySet if elementAccessExpressionNode.argumentExpression is set string value', () => { 117 const key = ts.factory.createStringLiteral('key'); 118 const value = ts.factory.createStringLiteral('value'); 119 const elementAccessExpression = ts.factory.createElementAccessExpression(key, value); 120 const propertySet = new Set<string>(); 121 getElementAccessExpressionProperties(elementAccessExpression); 122 expect(stringPropsSet.has('value')).to.be.true; 123 }); 124 125 it('should not add items to propertySet if elementAccessExpressionNode.argumentExpression is set int value', () => { 126 const key = ts.factory.createIdentifier('key'); 127 const value = ts.factory.createBigIntLiteral("9999999"); 128 const elementAccessExpression = ts.factory.createElementAccessExpression(key, value); 129 const propertySet = new Set<string>(); 130 getElementAccessExpressionProperties(elementAccessExpression) 131 expect(stringPropsSet.has('9999999')).to.be.false; 132 }); 133 }) 134 135 describe('test for getIndexedAccessTypeProperties function', function () { 136 beforeEach(() => { 137 stringPropsSet.clear(); 138 let cachePath = 'test/ut/utils/obfuscation'; 139 initProjectWhiteListManager(cachePath, false, false); 140 projectWhiteListManager?.setCurrentCollector('demo.ts'); 141 }); 142 143 afterEach(()=>{ 144 clearProjectWhiteListManager(); 145 }); 146 147 it('should not add items to propertySet if indexedAccessType is undefined', () => { 148 getIndexedAccessTypeProperties(undefined); 149 expect(stringPropsSet.has('value')).to.be.false; 150 expect(projectWhiteListManager?.fileWhiteListInfo.fileKeepInfo.stringProperties.has('value')).to.be.false; 151 }); 152 153 it('should add to propertySet if indexedAccessType.indexType is literalType and set string value', () => { 154 const indexedAccessType = ts.factory.createIndexedAccessTypeNode( 155 ts.factory.createTypeReferenceNode( 156 ts.factory.createIdentifier("T"), 157 undefined 158 ), 159 ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral("U")) 160 ) 161 getIndexedAccessTypeProperties(indexedAccessType); 162 expect(stringPropsSet.has("U")).to.be.true; 163 expect(projectWhiteListManager?.fileWhiteListInfo.fileKeepInfo.stringProperties.has("U")).to.be.true; 164 }); 165 166 it('should add to propertySet if indexedAccessType.indexType is unionType and set string value', () => { 167 const indexedAccessType = ts.factory.createIndexedAccessTypeNode( 168 ts.factory.createTypeReferenceNode( 169 ts.factory.createIdentifier("T1"), 170 undefined 171 ), 172 ts.factory.createUnionTypeNode([ 173 ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral("U")), 174 ts.factory.createLiteralTypeNode(ts.factory.createNumericLiteral(1)) 175 ]) 176 ) 177 getIndexedAccessTypeProperties(indexedAccessType); 178 expect(stringPropsSet.has("U")).to.be.true; 179 expect(stringPropsSet.has('1')).to.be.false; 180 expect(projectWhiteListManager?.fileWhiteListInfo.fileKeepInfo.stringProperties.has("U")).to.be.true; 181 expect(projectWhiteListManager?.fileWhiteListInfo.fileKeepInfo.stringProperties.has('1')).to.be.false; 182 }); 183 184 it('should not add items to propertySet if indexedAccessType.literalType is set numberic value', () => { 185 const indexedAccessType = ts.factory.createIndexedAccessTypeNode( 186 ts.factory.createTypeReferenceNode( 187 ts.factory.createIdentifier("T"), 188 undefined 189 ), 190 ts.factory.createLiteralTypeNode(ts.factory.createNumericLiteral(1)) 191 ) 192 getIndexedAccessTypeProperties(indexedAccessType) 193 expect(stringPropsSet.has('1')).to.be.false; 194 expect(projectWhiteListManager?.fileWhiteListInfo.fileKeepInfo.stringProperties.has('1')).to.be.false; 195 }); 196 }) 197 198 describe('test for getInterfaceProperties function', function () { 199 it('should not add items to propertySet if interfaceNode is undefined', () => { 200 const propertySet = new Set<string>(); 201 getInterfaceProperties(undefined, propertySet); 202 expect(stringPropsSet.has('property')).to.be.false; 203 }); 204 205 it('should add to propertySet if member.name is set string value', () => { 206 const members = [ 207 ts.factory.createPropertySignature([], undefined, undefined, undefined), 208 ts.factory.createPropertySignature([], ts.factory.createStringLiteral('property'), undefined, undefined) 209 ]; 210 const interfaceNode = ts.factory.createInterfaceDeclaration(undefined, 'Interface', undefined, undefined, members); 211 const propertySet = new Set<string>(); 212 getInterfaceProperties(interfaceNode, propertySet); 213 expect(stringPropsSet.has('property')).to.be.true; 214 expect(propertySet.has('property')).to.be.true; 215 }); 216 }) 217 218 describe('test for getClassProperties function', function () { 219 it('should not add items to propertySet if classNode is undefined', () => { 220 const propertySet = new Set<string>(); 221 getClassProperties(undefined, propertySet); 222 expect(propertySet.size == 0).to.be.true; 223 }); 224 225 it('should add to propertySet if classNode is StructDeclaration', () => { 226 const classProperty = ts.factory.createClassExpression( 227 undefined, 228 undefined, 229 undefined, 230 undefined, 231 undefined, 232 [] 233 ); 234 const parameters = [ 235 ts.factory.createParameterDeclaration( 236 [ts.factory.createModifier(ts.SyntaxKind.AbstractKeyword)], 237 undefined, 238 'parameter', 239 undefined, 240 ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), 241 undefined 242 ), 243 ts.factory.createParameterDeclaration( 244 [ts.factory.createModifier(ts.SyntaxKind.PublicKeyword)], 245 undefined, 246 'classParameter', 247 undefined, 248 ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), 249 classProperty 250 ) 251 ]; 252 const expression = ts.factory.createBinaryExpression( 253 ts.factory.createIdentifier('left'), 254 ts.SyntaxKind.EqualsToken, 255 ts.factory.createIdentifier('right') 256 ); 257 const statements = [ts.factory.createExpressionStatement(expression)]; 258 const members = [ 259 undefined, 260 ts.factory.createPropertyDeclaration(undefined, 'name', undefined, undefined, undefined), 261 ts.factory.createConstructorDeclaration( 262 undefined, 263 undefined, 264 parameters, 265 ts.factory.createBlock(statements, true) 266 ) 267 ]; 268 const structDeclaration = ts.factory.createStructDeclaration(undefined, undefined, undefined, undefined, members); 269 const propertySet = new Set<string>(); 270 getClassProperties(structDeclaration, propertySet); 271 expect(structPropsSet.has('name')).to.be.true; 272 expect(propertySet.has('parameter')).to.be.false; 273 expect(propertySet.has('classParameter')).to.be.true; 274 }); 275 276 describe('test for getEnumProperties function', function () { 277 it('should not add items to propertySet if enumNode is undefined', () => { 278 const propertySet = new Set<string>(); 279 getEnumProperties(undefined, propertySet); 280 expect(propertySet.size === 0).to.be.true; 281 }); 282 283 it('should add to propertySet if member.name is set', () => { 284 const members = [ 285 undefined, 286 ts.factory.createEnumMember('enumMember', ts.factory.createIdentifier('enumMember')), 287 ]; 288 const enumNode = ts.factory.createEnumDeclaration(undefined, undefined, 'enum', members); 289 const propertySet = new Set<string>(); 290 getEnumProperties(enumNode, propertySet); 291 expect(propertySet.has('enumMember')).to.be.true; 292 }); 293 }) 294 295 describe('test for getObjectProperties function', function () { 296 it('should not add items to propertySet if objNode is undefined', () => { 297 const propertySet = new Set<string>(); 298 getObjectProperties(undefined, propertySet); 299 expect(propertySet.size === 0).to.be.true; 300 }); 301 302 it('should add to propertySet if property.name is set', () => { 303 const objProperties = [ 304 ts.factory.createPropertyAssignment('objKey', ts.factory.createStringLiteral('objValue')) 305 ]; 306 const obj = ts.factory.createObjectLiteralExpression(objProperties); 307 const properties = [ 308 undefined, 309 ts.factory.createPropertyAssignment('key', obj), 310 ts.factory.createShorthandPropertyAssignment('key2', obj) 311 ]; 312 const objNode = ts.factory.createObjectLiteralExpression(properties, true); 313 const propertySet = new Set<string>(); 314 getObjectProperties(objNode, propertySet); 315 expect(propertySet.has('key')).to.be.true; 316 expect(propertySet.has('objKey')).to.be.true; 317 }); 318 }) 319 320 describe('test for getViewPUClassProperties function', function () { 321 it('should collectReservedStruct', () => { 322 const fileContent = ` 323 class A { 324 ["name1"] = "aa"; 325 "name2" = 2; 326 name3 = 3; 327 } 328 `; 329 let cachePath = 'test/ut/utils/obfuscation'; 330 const sourceFile: ts.SourceFile = ts.createSourceFile('demo.ts', fileContent, ts.ScriptTarget.ES2015, true); 331 UnobfuscationCollections.reservedStruct.clear(); 332 initProjectWhiteListManager(cachePath, false, false); 333 projectWhiteListManager?.setCurrentCollector('demo.ts'); 334 getViewPUClassProperties(sourceFile.statements[0] as ts.ClassDeclaration); 335 expect(UnobfuscationCollections.reservedStruct.has("name1")).to.be.true; 336 expect(UnobfuscationCollections.reservedStruct.has("name2")).to.be.true; 337 expect(UnobfuscationCollections.reservedStruct.has("name3")).to.be.true; 338 expect(projectWhiteListManager!.fileWhiteListInfo.fileKeepInfo.structProperties.has("name1")).to.be.true; 339 expect(projectWhiteListManager!.fileWhiteListInfo.fileKeepInfo.structProperties.has("name2")).to.be.true; 340 expect(projectWhiteListManager!.fileWhiteListInfo.fileKeepInfo.structProperties.has("name3")).to.be.true; 341 }); 342 }) 343 }) 344}); 345