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  stringPropsSet,
20  structPropsSet,
21  getTypeAliasProperties,
22  getInterfaceProperties,
23  getClassProperties,
24  getEnumProperties,
25  getObjectProperties
26} from '../../../src/utils/OhsUtil';
27import { describe, it } from 'mocha';
28import { expect } from 'chai';
29import * as ts from 'typescript';
30
31describe('unit test for OhsUtil.ts', function () {
32  describe('test for isViewPUBasedClass function', function () {
33    it('should return false if classNode is an empty object', () => {
34      const classNode = {} as any;
35      expect(isViewPUBasedClass(classNode)).to.be.false;
36    });
37
38    it('should return false if heritageClauses is undefined', () => {
39      const classNode = ts.factory.createClassDeclaration(undefined, "Class", undefined, undefined, []);
40      expect(isViewPUBasedClass(classNode)).to.be.false;
41    });
42
43    it('should return false if classNode is undefined', () => {
44      expect(isViewPUBasedClass(undefined)).to.be.false;
45    });
46
47    it('should return false if heritageClause.types is undefined', () => {
48      const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, undefined);
49      const classNode = ts.factory.createClassDeclaration(undefined, "Class", undefined, [heritageClause], []);
50      expect(isViewPUBasedClass(classNode)).to.be.false;
51    });
52
53    it('should return false if classNode.heritageClause.types.member is undefined', () => {
54      const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [undefined]);
55      const classNode = ts.factory.createClassDeclaration(undefined, "Class", undefined, [heritageClause], []);
56      expect(isViewPUBasedClass(classNode)).to.be.false;
57    })
58
59    it('should return true if classNode is set', () => {
60      const typeArguments = [
61        ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
62      ];
63      const type = ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('ViewPU'), typeArguments);
64      const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [type]);
65      const classNode = ts.factory.createClassDeclaration(undefined, "Class", undefined, [heritageClause], []);
66      expect(isViewPUBasedClass(classNode)).to.be.true;
67    });
68  })
69
70  describe('test for getTypeAliasProperties function', function () {
71    it('should not add items to propertySet if type is undefined', () => {
72      const name = ts.factory.createIdentifier('MyType');
73      const typeAliasNode = ts.factory.createTypeAliasDeclaration(undefined, name, undefined, undefined);
74      const propertySet = new Set<string>();
75      getTypeAliasProperties(typeAliasNode, propertySet);
76      expect(stringPropsSet.size == 0).to.be.true;
77    });
78
79    it('should add to propertySet if member.name is set', () => {
80      const name = ts.factory.createIdentifier('MyType');
81      const type = ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
82      const identifierName = ts.factory.createIdentifier('Identifier');
83      const stringName = ts.factory.createStringLiteral('String');
84      const computedPropertyName = ts.factory.createComputedPropertyName(ts.factory.createStringLiteral('3 + 2'));
85      const types = ts.factory.createTypeLiteralNode([
86        ts.factory.createPropertySignature(undefined, undefined, undefined, type),
87        ts.factory.createPropertySignature(undefined, identifierName, undefined, type),
88        ts.factory.createPropertySignature(undefined, stringName, undefined, type),
89        ts.factory.createPropertySignature(undefined, computedPropertyName, undefined, type),
90      ]);
91      const typeAliasNode = ts.factory.createTypeAliasDeclaration(undefined, name, undefined, types);
92      const propertySet = new Set<string>();
93      getTypeAliasProperties(typeAliasNode, propertySet);
94      expect(propertySet.has('Identifier') && propertySet.has('String') && propertySet.has('3 + 2')).to.be.true;
95      expect(stringPropsSet.has('String') && propertySet.has('3 + 2')).to.be.true;
96    });
97  })
98
99  describe('test for getElementAccessExpressionProperties function', function () {
100    it('should not add items to propertySet if elementAccessExpression is undefined', () => {
101      const propertySet = new Set<string>();
102      getElementAccessExpressionProperties(undefined, propertySet);
103      expect(stringPropsSet.has('value')).to.be.false;
104    });
105
106    it('should add to propertySet if elementAccessExpressionNode.argumentExpression is set string value', () => {
107      const key = ts.factory.createStringLiteral('key');
108      const value = ts.factory.createStringLiteral('value');
109      const elementAccessExpression = ts.factory.createElementAccessExpression(key, value);
110      const propertySet = new Set<string>();
111      getElementAccessExpressionProperties(elementAccessExpression, propertySet);
112      expect(stringPropsSet.has('value')).to.be.true;
113    });
114
115    it('should not add items to propertySet if elementAccessExpressionNode.argumentExpression is set int value', () => {
116      const key = ts.factory.createIdentifier('key');
117      const value = ts.factory.createBigIntLiteral("9999999");
118      const elementAccessExpression = ts.factory.createElementAccessExpression(key, value);
119      const propertySet = new Set<string>();
120      getElementAccessExpressionProperties(elementAccessExpression, propertySet)
121      expect(stringPropsSet.has('9999999')).to.be.false;
122    });
123  })
124
125  describe('test for getInterfaceProperties function', function () {
126    it('should not add items to propertySet if interfaceNode is undefined', () => {
127      const propertySet = new Set<string>();
128      getInterfaceProperties(undefined, propertySet);
129      expect(stringPropsSet.has('property')).to.be.false;
130    });
131
132    it('should add to propertySet if member.name is set string value', () => {
133      const members = [
134        ts.factory.createPropertySignature([], undefined, undefined, undefined),
135        ts.factory.createPropertySignature([], ts.factory.createStringLiteral('property'), undefined, undefined)
136      ];
137      const interfaceNode = ts.factory.createInterfaceDeclaration(undefined, 'Interface', undefined, undefined, members);
138      const propertySet = new Set<string>();
139      getInterfaceProperties(interfaceNode, propertySet);
140      expect(stringPropsSet.has('property')).to.be.true;
141      expect(propertySet.has('property')).to.be.true;
142    });
143  })
144
145  describe('test for getClassProperties function', function () {
146    it('should not add items to propertySet if classNode is undefined', () => {
147      const propertySet = new Set<string>();
148      getClassProperties(undefined, propertySet);
149      expect(propertySet.size == 0).to.be.true;
150    });
151
152    it('should add to propertySet if classNode is StructDeclaration', () => {
153      const classProperty = ts.factory.createClassExpression(
154        undefined,
155        undefined,
156        undefined,
157        undefined,
158        undefined,
159        []
160      );
161      const parameters = [
162        ts.factory.createParameterDeclaration(
163          [ts.factory.createModifier(ts.SyntaxKind.AbstractKeyword)],
164          undefined,
165          'parameter',
166          undefined,
167          ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
168          undefined
169        ),
170        ts.factory.createParameterDeclaration(
171          [ts.factory.createModifier(ts.SyntaxKind.PublicKeyword)],
172          undefined,
173          'classParameter',
174          undefined,
175          ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
176          classProperty
177        )
178      ];
179      const expression = ts.factory.createBinaryExpression(
180        ts.factory.createIdentifier('left'),
181        ts.SyntaxKind.EqualsToken,
182        ts.factory.createIdentifier('right')
183      );
184      const statements = [ts.factory.createExpressionStatement(expression)];
185      const members = [
186        undefined,
187        ts.factory.createPropertyDeclaration(undefined, 'name', undefined, undefined, undefined),
188        ts.factory.createConstructorDeclaration(
189          undefined,
190          undefined,
191          parameters,
192          ts.factory.createBlock(statements, true)
193        )
194      ];
195      const structDeclaration = ts.factory.createStructDeclaration(undefined, undefined, undefined, undefined, members);
196      const propertySet = new Set<string>();
197      getClassProperties(structDeclaration, propertySet);
198      expect(structPropsSet.has('name')).to.be.true;
199      expect(propertySet.has('parameter')).to.be.false;
200      expect(propertySet.has('classParameter')).to.be.true;
201    });
202
203    describe('test for getEnumProperties function', function () {
204      it('should not add items to propertySet if enumNode is undefined', () => {
205        const propertySet = new Set<string>();
206        getEnumProperties(undefined, propertySet);
207        expect(propertySet.size === 0).to.be.true;
208      });
209
210      it('should add to propertySet if member.name is set', () => {
211        const members = [
212          undefined,
213          ts.factory.createEnumMember('enumMember', ts.factory.createIdentifier('enumMember')),
214        ];
215        const enumNode = ts.factory.createEnumDeclaration(undefined, undefined, 'enum', members);
216        const propertySet = new Set<string>();
217        getEnumProperties(enumNode, propertySet);
218        expect(propertySet.has('enumMember')).to.be.true;
219      });
220    })
221
222    describe('test for getObjectProperties function', function () {
223      it('should not add items to propertySet if objNode is undefined', () => {
224        const propertySet = new Set<string>();
225        getObjectProperties(undefined, propertySet);
226        expect(propertySet.size === 0).to.be.true;
227      });
228
229      it('should add to propertySet if property.name is set', () => {
230        const objProperties = [
231          ts.factory.createPropertyAssignment('objKey', ts.factory.createStringLiteral('objValue'))
232        ];
233        const obj = ts.factory.createObjectLiteralExpression(objProperties);
234        const properties = [
235          undefined,
236          ts.factory.createPropertyAssignment('key', obj),
237          ts.factory.createShorthandPropertyAssignment('key2', obj)
238        ];
239        const objNode = ts.factory.createObjectLiteralExpression(properties, true);
240        const propertySet = new Set<string>();
241        getObjectProperties(objNode, propertySet);
242        expect(propertySet.has('key')).to.be.true;
243        expect(propertySet.has('objKey')).to.be.true;
244      });
245    })
246  })
247}); 
248