• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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})