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 { describe, it } from 'mocha'; 17import { expect } from 'chai'; 18import { NodeUtils } from '../../../src/utils/NodeUtils' 19import * as ts from 'typescript' 20import sinon from 'sinon'; 21 22type Mutable<T extends object> = { -readonly [K in keyof T]: T[K] } 23 24describe('test for NodeUtils', function () { 25 describe('test for isPropertyDeclarationNode', function () { 26 it('should return false if node has no parent', function () { 27 const node = ts.factory.createIdentifier('name'); 28 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.false; 29 }) 30 it('should return ture when node.parent is PropertyAssignment', function () { 31 const node = ts.factory.createIdentifier('name'); 32 const parent = ts.factory.createPropertyAssignment(node, ts.factory.createNumericLiteral('1')); 33 (node as Mutable<ts.Node>).parent = parent; 34 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 35 }) 36 it('should return ture when node.parent is ComputedPropertyName', function () { 37 const node = ts.factory.createIdentifier('name'); 38 const parent = ts.factory.createComputedPropertyName(node); 39 (node as Mutable<ts.Node>).parent = parent; 40 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 41 }) 42 it('should return ture when node.parent is BindingElement', function () { 43 const node = ts.factory.createIdentifier('name'); 44 const parent = ts.factory.createBindingElement(undefined, node, 'bindingElement'); 45 (node as Mutable<ts.Node>).parent = parent; 46 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 47 }) 48 it('should return ture when node.parent is PropertySignature', function () { 49 const node = ts.factory.createIdentifier('name'); 50 const parent = ts.factory.createPropertySignature(undefined, node, undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)); 51 (node as Mutable<ts.Node>).parent = parent; 52 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 53 }) 54 it('should return ture when node.parent is MethodSignature', function () { 55 const node = ts.factory.createIdentifier('name'); 56 const parent = ts.factory.createMethodSignature(undefined, node, undefined, undefined, [], undefined); 57 (node as Mutable<ts.Node>).parent = parent; 58 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 59 }) 60 it('should return ture when node.parent is EnumMember', function () { 61 const node = ts.factory.createIdentifier('name'); 62 const parent = ts.factory.createEnumMember(node); 63 (node as Mutable<ts.Node>).parent = parent; 64 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 65 }) 66 it('should return ture when node.parent is PropertyDeclaration', function () { 67 const node = ts.factory.createIdentifier('name'); 68 const parent = ts.factory.createPropertyDeclaration(undefined, undefined, node, undefined, undefined, undefined); 69 (node as Mutable<ts.Node>).parent = parent; 70 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 71 }) 72 it('should return ture when node.parent is MethodDeclaration', function () { 73 const node = ts.factory.createIdentifier('name'); 74 const parent = ts.factory.createMethodDeclaration(undefined, undefined, undefined, node, undefined, undefined, [], undefined, undefined); 75 (node as Mutable<ts.Node>).parent = parent; 76 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 77 }) 78 it('should return ture when node.parent is SetAccessorDeclaration', function () { 79 const node = ts.factory.createIdentifier('name'); 80 const parent = ts.factory.createSetAccessorDeclaration(undefined, undefined, node, [], undefined); 81 (node as Mutable<ts.Node>).parent = parent; 82 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 83 }) 84 it('should return ture when node.parent is GetAccessorDeclaration', function () { 85 const node = ts.factory.createIdentifier('name'); 86 const parent = ts.factory.createGetAccessorDeclaration(undefined, undefined, node, [], undefined, undefined); 87 (node as Mutable<ts.Node>).parent = parent; 88 expect(NodeUtils.isPropertyDeclarationNode(node)).to.be.true; 89 }) 90 }) 91 describe('test for isPropertyOrElementAccessNode', function () { 92 let isPropertyAccessNodeStub; 93 let isElementAccessNodeStub; 94 95 beforeEach(function () { 96 isPropertyAccessNodeStub = sinon.stub(NodeUtils, 'isPropertyAccessNode').returns(false); 97 isElementAccessNodeStub = sinon.stub(NodeUtils, 'isElementAccessNode').returns(false); 98 }); 99 100 afterEach(function () { 101 isPropertyAccessNodeStub.restore(); 102 isElementAccessNodeStub.restore(); 103 }); 104 105 it('should return true when node is a PropertyAccessNode', function () { 106 const node = ts.factory.createIdentifier('name'); 107 isPropertyAccessNodeStub.returns(true); 108 expect(NodeUtils.isPropertyOrElementAccessNode(node)).to.be.true; 109 }) 110 it('should return true when node is a isElementAccessNode', function () { 111 const node = ts.factory.createIdentifier('name'); 112 isElementAccessNodeStub.returns(true); 113 expect(NodeUtils.isPropertyOrElementAccessNode(node)).to.be.true; 114 }) 115 it('should return false when both isPropertyAccessNode and isElementAccessNode return false', function () { 116 const node = ts.factory.createIdentifier('name'); 117 expect(NodeUtils.isPropertyOrElementAccessNode(node)).to.be.false; 118 }) 119 }) 120 describe('test for isPropertyAccessNode', function () { 121 let isInClassDeclarationStub; 122 let isInExpressionStub; 123 124 beforeEach(function () { 125 isInClassDeclarationStub = sinon.stub(NodeUtils, 'isInClassDeclaration').returns(false); 126 isInExpressionStub = sinon.stub(NodeUtils, 'isInExpression').returns(false); 127 }); 128 129 afterEach(function () { 130 isInClassDeclarationStub.restore(); 131 isInExpressionStub.restore(); 132 }); 133 134 it('should return false if node has no parent', function () { 135 const node = ts.factory.createIdentifier('name'); 136 expect(NodeUtils.isPropertyAccessNode(node)).to.be.false; 137 }) 138 it('should return true if isPropertyAccessExpression and parent.name equals to node', function () { 139 const node = ts.factory.createIdentifier('name'); 140 const parent = ts.factory.createPropertyAccessExpression(node, node); 141 (node as Mutable<ts.Node>).parent = parent; 142 expect(NodeUtils.isPropertyAccessNode(node)).to.be.true; 143 }) 144 it('should return isInExpression(parent) if isPrivateIdentifier and isInClassDeclaration', function () { 145 const node = ts.factory.createPrivateIdentifier("#name"); 146 const parent = ts.factory.createIdentifier('parent'); 147 (node as Mutable<ts.Node>).parent = parent; 148 isInClassDeclarationStub.returns(true); 149 isInExpressionStub.returns(true) 150 expect(NodeUtils.isPropertyAccessNode(node)).to.be.true; 151 isInExpressionStub.returns(false) 152 expect(NodeUtils.isPropertyAccessNode(node)).to.be.false; 153 }) 154 it('should return true if isQualifiedName and parent.right equals to node', function () { 155 const node = ts.factory.createIdentifier('name'); 156 const parent = ts.factory.createQualifiedName(node, node); 157 (node as Mutable<ts.Node>).parent = parent; 158 expect(NodeUtils.isPropertyAccessNode(node)).to.be.true; 159 }) 160 }) 161 describe('test for isInClassDeclaration', function () { 162 it('should return flase when node is undefined', function () { 163 expect(NodeUtils.isInClassDeclarationForTest(undefined)).to.be.false; 164 }) 165 it('should return true when node is ClassDeclaration', function () { 166 const node = ts.factory.createClassDeclaration(undefined, undefined, undefined, undefined, undefined, []); 167 expect(NodeUtils.isInClassDeclarationForTest(node)).to.be.true; 168 }) 169 it('should return true when node is ClassExpression', function () { 170 const node = ts.factory.createClassExpression(undefined, undefined, undefined, undefined, undefined, []); 171 expect(NodeUtils.isInClassDeclarationForTest(node)).to.be.true; 172 }) 173 it('should return true when node.parent is isInClassDeclaration', function () { 174 const node = ts.factory.createIdentifier('name'); 175 const parent = ts.factory.createClassExpression(undefined, undefined, undefined, undefined, undefined, []); 176 (node as Mutable<ts.Node>).parent = parent; 177 expect(NodeUtils.isInClassDeclarationForTest(node)).to.be.true; 178 }) 179 }) 180 describe('test for isInClassDeclaration', function () { 181 it('should return flase when node is undefined', function () { 182 expect(NodeUtils.isInClassDeclarationForTest(undefined)).to.be.false; 183 }) 184 it('should return true when node is ClassDeclaration', function () { 185 const node = ts.factory.createClassDeclaration(undefined, undefined, undefined, undefined, undefined, []); 186 expect(NodeUtils.isInClassDeclarationForTest(node)).to.be.true; 187 }) 188 it('should return true when node is ClassExpression', function () { 189 const node = ts.factory.createClassExpression(undefined, undefined, undefined, undefined, undefined, []); 190 expect(NodeUtils.isInClassDeclarationForTest(node)).to.be.true; 191 }) 192 it('should return true when node.parent is isInClassDeclaration', function () { 193 const node = ts.factory.createIdentifier('name'); 194 const parent = ts.factory.createClassExpression(undefined, undefined, undefined, undefined, undefined, []); 195 (node as Mutable<ts.Node>).parent = parent; 196 expect(NodeUtils.isInClassDeclarationForTest(node)).to.be.true; 197 }) 198 }) 199 describe('test for isInExpression', function () { 200 it('should return flase when node is undefined', function () { 201 expect(NodeUtils.isInExpressionForTest(undefined)).to.be.false; 202 }) 203 it('should return isInOperator(node) when node is not undefined', function () { 204 let isInOperatorStub = sinon.stub(NodeUtils, 'isInOperator').returns(false); 205 const node = ts.factory.createIdentifier('name'); 206 expect(NodeUtils.isInExpressionForTest(node)).to.be.false; 207 isInOperatorStub.returns(true); 208 expect(NodeUtils.isInExpressionForTest(node)).to.be.true; 209 isInOperatorStub.restore(); 210 }) 211 }) 212 describe('test for isInOperator', function () { 213 it('should return true when node is binary expression and operator is InKeyword', function () { 214 const name = ts.factory.createIdentifier('name'); 215 const node = ts.factory.createBinaryExpression(name, ts.SyntaxKind.InKeyword, name); 216 expect(NodeUtils.isInOperatorForTest(node)).to.be.true; 217 }) 218 it('should return false when node is not binary expression', function () { 219 const node = ts.factory.createIdentifier('name'); 220 expect(NodeUtils.isInOperatorForTest(node)).to.be.false; 221 }) 222 it('should return false when operator is not Inkeyword', function () { 223 const name = ts.factory.createIdentifier('name'); 224 const node = ts.factory.createBinaryExpression(name, ts.SyntaxKind.PlusEqualsToken, name); 225 expect(NodeUtils.isInOperatorForTest(node)).to.be.false; 226 }) 227 }) 228 229 describe('test for isElementAccessNode', function () { 230 it('should return false if node has no parent', function () { 231 const node = ts.factory.createIdentifier('name'); 232 expect(NodeUtils.isElementAccessNode(node)).to.be.false; 233 }) 234 it('should return true if isElementAccessExpression and parent argumentExpression equals to node', function () { 235 const node = ts.factory.createIdentifier('name'); 236 const parent = ts.factory.createElementAccessExpression(node, node); 237 (node as Mutable<ts.Node>).parent = parent; 238 }) 239 }) 240 241 describe('test for isClassPropertyInConstructorParams', function () { 242 it('should return false if node is not an Identifier', function () { 243 const node = ts.factory.createRegularExpressionLiteral('name'); 244 expect(NodeUtils.isClassPropertyInConstructorParams(node)).to.be.false; 245 }) 246 it('should return false when node has no parent', function () { 247 const node = ts.factory.createIdentifier('name'); 248 expect(NodeUtils.isClassPropertyInConstructorParams(node)).to.be.false; 249 }) 250 it('should return false when node parent is not a parameter', function () { 251 const node = ts.factory.createIdentifier('name'); 252 const parent = ts.factory.createElementAccessExpression(node, node); 253 (node as Mutable<ts.Node>).parent = parent; 254 expect(NodeUtils.isClassPropertyInConstructorParams(node)).to.be.false; 255 }) 256 it('should return false when modifiers is undefined', function () { 257 const node = ts.factory.createIdentifier('name'); 258 const parent = ts.factory.createParameterDeclaration([], undefined, node, undefined, undefined, undefined); 259 (node as Mutable<ts.Node>).parent = parent; 260 expect(NodeUtils.isClassPropertyInConstructorParams(node)).to.be.false; 261 }) 262 it('should return false when modifiers length is 0 or modifier is ParameterPropertyModifier', function () { 263 const node = ts.factory.createIdentifier('name'); 264 const parent = ts.factory.createParameterDeclaration([ts.factory.createModifier(ts.SyntaxKind.AbstractKeyword)], undefined, node, undefined, undefined, undefined); 265 (node as Mutable<ts.Node>).parent = parent; 266 expect(NodeUtils.isClassPropertyInConstructorParams(node)).to.be.false; 267 }) 268 it('should return true when node parent parent is ConstructorDeclaration', function () { 269 const node = ts.factory.createIdentifier('name'); 270 const parent = ts.factory.createParameterDeclaration([ts.factory.createModifier(ts.SyntaxKind.PublicKeyword)], undefined, node, undefined, undefined, undefined); 271 const parentParent = ts.factory.createConstructorDeclaration(undefined, [ts.factory.createModifier(ts.SyntaxKind.AbstractKeyword)], [], undefined); 272 (parent as Mutable<ts.Node>).parent = parentParent; 273 (node as Mutable<ts.Node>).parent = parent; 274 expect(NodeUtils.isClassPropertyInConstructorParams(node)).to.be.true; 275 }) 276 }) 277 278 describe('test for isClassPropertyInConstructorBody', function () { 279 it('should return false if node is not an Identifier', function () { 280 const node = ts.factory.createRegularExpressionLiteral('name'); 281 expect(NodeUtils.isClassPropertyInConstructorBody(node, new Set)).to.be.false; 282 }) 283 it('shound return true when node parent is ConstructorDeclaration and constructorParams has id', function () { 284 const node = ts.factory.createIdentifier('name'); 285 const set: Set<string> = new Set(); 286 set.add('name'); 287 const parent = ts.factory.createConstructorDeclaration(undefined, [ts.factory.createModifier(ts.SyntaxKind.AbstractKeyword)], [], undefined); 288 (node as Mutable<ts.Node>).parent = parent; 289 expect(NodeUtils.isClassPropertyInConstructorBody(node, set)).to.be.true; 290 }) 291 it('should return false when curNode is not a ConstructorDeclaration or id does not exist in constructorParams', function () { 292 const node = ts.factory.createIdentifier('name'); 293 const set: Set<string> = new Set(); 294 set.add('test'); 295 const parent = ts.factory.createElementAccessExpression(node, node); 296 (node as Mutable<ts.Node>).parent = parent; 297 expect(NodeUtils.isClassPropertyInConstructorBody(node, set)).to.be.false; 298 }) 299 }) 300 301 describe('test for isPropertyNode', function () { 302 it('should return true when node is PropertyOrElementAccessNode', function () { 303 const node = ts.factory.createIdentifier('name'); 304 const parent = ts.factory.createElementAccessExpression(node, node); 305 (node as Mutable<ts.Node>).parent = parent; 306 expect(NodeUtils.isPropertyNode(node)).to.be.true; 307 }) 308 it('should return true when node is a PropertyDeclarationNode', function () { 309 const node = ts.factory.createIdentifier('name'); 310 const parent = ts.factory.createPropertyAssignment(node, node); 311 (node as Mutable<ts.Node>).parent = parent; 312 expect(NodeUtils.isPropertyNode(node)).to.be.true; 313 }) 314 }) 315 316 describe('test for isObjectBindingPatternAssignment', function () { 317 it('should return false when node is not VariableDeclaration', function () { 318 const node = ts.factory.createObjectBindingPattern([]); 319 const parent = ts.factory.createParameterDeclaration(undefined, undefined, undefined, node, undefined, undefined, undefined); 320 (node as Mutable<ts.Node>).parent = parent; 321 expect(NodeUtils.isObjectBindingPatternAssignment(node)).to.be.false; 322 }) 323 it('should return true when node parent initializer is CallExpression', function () { 324 const node = ts.factory.createObjectBindingPattern([]); 325 const parent = ts.factory.createVariableDeclaration(node, undefined, undefined, undefined); 326 const initializer = ts.factory.createCallExpression(ts.factory.createIdentifier('name'), undefined, undefined); 327 (parent as Mutable<ts.VariableDeclaration>).initializer = initializer; 328 (node as Mutable<ts.Node>).parent = parent; 329 expect(NodeUtils.isObjectBindingPatternAssignment(node)).to.be.true; 330 }) 331 }) 332 333 describe('test for isDeclarationFile', function () { 334 it('should return false when sourceFile is not a declarationFile', function () { 335 const endOfFileToken = ts.factory.createToken(ts.SyntaxKind.EndOfFileToken); 336 const sourceFile = ts.factory.createSourceFile([], endOfFileToken, ts.NodeFlags.AwaitContext); 337 expect(NodeUtils.isDeclarationFile(sourceFile)).to.be.false; 338 }) 339 }) 340 341 describe('test for getSourceFileOfNode', function () { 342 it('should return node when node kind is SyntaxKind.SourceFile', function () { 343 const node = ts.factory.createIdentifier('name'); 344 const kind = ts.SyntaxKind.SourceFile; 345 (node as Mutable<ts.Node>).kind = kind; 346 expect(NodeUtils.getSourceFileOfNode(node)).to.equal(node); 347 }) 348 it('should return node parent when node kind is not SyntaxKind.SourceFile', function () { 349 const node = ts.factory.createIdentifier('name'); 350 const kind = ts.SyntaxKind.SymbolKeyword; 351 (node as Mutable<ts.Node>).kind = kind; 352 const endOfFileToken = ts.factory.createToken(ts.SyntaxKind.EndOfFileToken); 353 const parent = ts.factory.createSourceFile([], endOfFileToken, ts.NodeFlags.AwaitContext); 354 (node as Mutable<ts.Node>).parent = parent; 355 expect(NodeUtils.getSourceFileOfNode(node)).to.equal(node.parent); 356 }) 357 }) 358 359 describe('test for isDETSFile', function () { 360 it('should return true when node fileName end with .d.ets', function () { 361 const node = ts.factory.createIdentifier('name'); 362 const kind = ts.SyntaxKind.SourceFile; 363 (node as Mutable<ts.Node>).kind = kind; 364 const sourceFile = NodeUtils.getSourceFileOfNode(node); 365 sourceFile.fileName = 'a.d.ets'; 366 expect(NodeUtils.isDETSFile(node)).to.be.true; 367 }) 368 }) 369 370 describe('test for isNewTargetNode', function () { 371 it('should return true when node parent is MetaProperty and node parent keywordToken is yntaxKind.NewKeyword and node escapedText is target', function () { 372 const node = ts.factory.createIdentifier('target'); 373 const parent = ts.factory.createMetaProperty(ts.SyntaxKind.NewKeyword, node); 374 (node as Mutable<ts.Identifier>).parent = parent; 375 expect(NodeUtils.isNewTargetNode(node)).to.be.true; 376 }) 377 it('should return false when node is not a new target node', function () { 378 const node = ts.factory.createIdentifier('name'); 379 const parent = ts.factory.createMetaProperty(ts.SyntaxKind.ImportKeyword, node); 380 (node as Mutable<ts.Identifier>).parent = parent; 381 expect(NodeUtils.isNewTargetNode(node)).to.be.false; 382 }) 383 }) 384})