• 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 { assert, expect } from 'chai';
18import {
19  ObOptionsForTest,
20  ObConfigResolver,
21  MergedConfig,
22  collectResevedFileNameInIDEConfig,
23  readNameCache,
24  handleUniversalPathInObf,
25  getArkguardNameCache,
26  fillNameCache,
27  writeObfuscationNameCache,
28  generateConsumerObConfigFile,
29  mangleFilePath,
30  enableObfuscatedFilePathConfig,
31  handleObfuscatedFilePath,
32  enableObfuscateFileName,
33  getRelativeSourcePath,
34  OptionTypeForTest,
35  SourceObConfig,
36  Obfuscation,
37  printUnobfuscationReasons,
38  clearNameCache
39} from '../../../src/initialization/ConfigResolver';
40import { HvigorErrorInfo, PropCollections, renameFileNameModule } from '../../../src/ArkObfuscator';
41import {
42  clearUnobfuscationNamesObj,
43  nameCacheMap,
44  unobfuscationNamesObj
45} from '../../../src/initialization/CommonObject';
46import path from 'path';
47import fs from 'fs';
48import { FileUtils } from '../../../src/utils/FileUtils';
49import sinon from 'sinon';
50import { AtKeepCollections, UnobfuscationCollections } from '../../../src/utils/CommonCollections';
51import {
52  clearHistoryUnobfuscatedMap,
53  historyAllUnobfuscatedNamesMap,
54  historyUnobfuscatedPropMap
55} from '../../../src/initialization/Initializer';
56
57const OBFUSCATE_TESTDATA_DIR = path.resolve(__dirname, '../../testData/obfuscation/system_api_obfuscation');
58const projectConfig = {
59  obfuscationOptions: { option1: 'value1' },
60  compileHar: true
61};
62
63function printObfLogger(errorInfo: string, errorCodeInfo: HvigorErrorInfo | string, level: string): void {
64  switch (level) {
65    case 'warn':
66      console.warn(errorInfo);
67      break;
68    case 'error':
69      console.error(errorInfo);
70      break;
71    default:
72      break;
73  }
74}
75
76function printObfHvigorLogger(errorInfo: string, errorCodeInfo: HvigorErrorInfo | string, level: string): void {
77  switch (level) {
78    case 'warn':
79      console.warn(errorCodeInfo);
80      break;
81    case 'error':
82      console.error(errorCodeInfo);
83      break;
84    default:
85      break;
86  }
87}
88
89const logger = console;
90const isTerser = false;
91let newObConfigResolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
92
93describe('test for ConfigResolve', function() {
94  describe('ObOptions', () => {
95    it('should merge options correctly', () => {
96      const ob1 = new ObOptionsForTest();
97      ob1.disableObfuscation = true;
98      ob1.enablePropertyObfuscation = true;
99
100      const ob2 = new ObOptionsForTest();
101      ob2.enableToplevelObfuscation = true;
102      ob2.printNameCache = 'test';
103      ob2.printKeptNamesPath = './test/ut/initialization/printKeptNamesPath.txt';
104      ob2.applyNameCache = 'test case';
105
106      ob1.mergeObOptions(ob2);
107
108      expect(ob1.disableObfuscation).to.be.true;
109      expect(ob1.enablePropertyObfuscation).to.be.true;
110      expect(ob1.enableToplevelObfuscation).to.be.true;
111      expect(ob1.printNameCache).to.equal('test');
112      expect(ob1.printKeptNamesPath).to.equal('./test/ut/initialization/printKeptNamesPath.txt');
113      expect(ob1.applyNameCache).to.equal('test case');
114    });
115  });
116
117  describe('MergedConfig', () => {
118    describe('should merge two MergedConfig instances correctly', () => {
119      it('merge arrays and sets in MergeConfig', () => {
120        const config1 = new MergedConfig();
121        config1.reservedPropertyNames = ['prop1'];
122        config1.reservedGlobalNames = ['global1'];
123        config1.keepComments = ['comment1'];
124        config1.excludePathSet.add('path1');
125
126        const config2 = new MergedConfig();
127        config2.reservedPropertyNames = ['prop2'];
128        config2.reservedGlobalNames = ['global2'];
129        config2.keepComments = ['comment2'];
130        config2.excludePathSet.add('path2');
131
132        config1.mergeAllRules(config2);
133
134        expect(config1.reservedPropertyNames).to.deep.equal(['prop1', 'prop2']);
135        expect(config1.reservedGlobalNames).to.deep.equal(['global1', 'global2']);
136        expect(config1.keepComments).to.deep.equal(['comment1', 'comment2']);
137        expect(config1.excludePathSet).to.deep.equal(new Set(['path1', 'path2']));
138      });
139
140      it('merge options in MergeConfig', () => {
141        const config1 = new MergedConfig();
142        config1.options.enableExportObfuscation = false;
143        config1.options.stripLanguageDefault = true;
144        config1.options.stripSystemApiArgs = true;
145
146        const config2 = new MergedConfig();
147        config2.options.enableExportObfuscation = true;
148        config2.options.stripLanguageDefault = false;
149        config2.options.stripSystemApiArgs = true;
150        config1.mergeAllRules(config2);
151
152        expect(config1.options.disableObfuscation).to.be.false;
153        expect(config1.options.enablePropertyObfuscation).to.be.false;
154        expect(config1.options.enableToplevelObfuscation).to.be.false;
155        expect(config1.options.enableStringPropertyObfuscation).to.be.false;
156        expect(config1.options.removeLog).to.be.false;
157        expect(config1.options.compact).to.be.false;
158        expect(config1.options.removeComments).to.be.false;
159        expect(config1.options.enableFileNameObfuscation).to.be.false;
160        expect(config1.options.enableExportObfuscation).to.be.true;
161        expect(config1.options.stripLanguageDefault).to.be.true;
162        expect(config1.options.stripSystemApiArgs).to.be.true;
163      });
164    });
165
166    it('should sort and deduplicate arrays correctly', () => {
167      const config = new MergedConfig();
168      config.reservedPropertyNames = ['prop2', 'prop1', 'prop1'];
169      config.reservedGlobalNames = ['global2', 'global1', 'global1'];
170      config.keepComments = ['comment2', 'comment1', 'comment1'];
171
172      config.sortAndDeduplicate();
173
174      expect(config.reservedPropertyNames).to.deep.equal(['prop1', 'prop2']);
175      expect(config.reservedGlobalNames).to.deep.equal(['global1', 'global2']);
176      expect(config.keepComments).to.deep.equal(['comment1', 'comment2']);
177    });
178
179    it('should serialize merged config correctly', () => {
180      let resultStr: string = '';
181      const config = new MergedConfig();
182      config.options = new ObOptionsForTest();
183      config.options['option1'] = true;
184      config.options['option2'] = false;
185      config.options['disableObfuscation'] = true;
186      config.options['enableStringPropertyObfuscation'] = true;
187      config.reservedGlobalNames = ['global1'];
188      config.reservedPropertyNames = ['prop1'];
189
190      const serialized = config.serializeMergedConfig();
191      const serializedExportSwitchMap = new Map([
192        ['disableObfuscation', ObConfigResolver.KEEP_DTS],
193        ['enablePropertyObfuscation', ObConfigResolver.ENABLE_PROPERTY_OBFUSCATION],
194        ['enableStringPropertyObfuscation', ObConfigResolver.ENABLE_STRING_PROPERTY_OBFUSCATION],
195        ['enableToplevelObfuscation', ObConfigResolver.ENABLE_TOPLEVEL_OBFUSCATION],
196        ['compact', ObConfigResolver.COMPACT],
197        ['removeLog', ObConfigResolver.REMOVE_LOG],
198      ]);
199
200      expect(serialized).to.include(ObConfigResolver.KEEP_GLOBAL_NAME);
201      expect(serialized).to.include('global1');
202      expect(serialized).to.include(ObConfigResolver.KEEP_PROPERTY_NAME);
203      expect(serialized).to.include('prop1');
204      expect(serialized).to.not.include('option2');
205
206      expect(ObConfigResolver.exportedSwitchMap.has(String('disableObfuscation'))).to.be.false;
207      expect(ObConfigResolver.exportedSwitchMap.has(String('enableStringPropertyObfuscation'))).to.be.true;
208      expect(resultStr).to.equal('');
209    });
210  });
211
212  describe('ObConfigResolver', () => {
213    describe('constructor', () => {
214      it('should create an instance with the correct properties', () => {
215        const projectConfig = {
216          obfuscationOptions: { option1: 'value1' },
217          compileHar: true
218        };
219        const isTerser = false;
220        const myInstance = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
221
222        expect(myInstance).to.be.an('object');
223        expect(myInstance.sourceObConfig).to.deep.equal({ option1: 'value1' });
224        expect(myInstance.isHarCompiled).to.be.true;
225        expect(myInstance.isTerser).to.be.false;
226      });
227
228      it('should create an instance with Terser enabled', () => {
229        const projectConfig = {
230          obfuscationOptions: { option1: 'value1' },
231          compileHar: true
232        };
233        const myInstance = new ObConfigResolver(projectConfig, printObfLogger, true);
234
235        expect(myInstance).to.be.an('object');
236        expect(myInstance.sourceObConfig).to.deep.equal({ option1: 'value1' });
237        expect(myInstance.isHarCompiled).to.be.true;
238        expect(myInstance.isTerser).to.be.true;
239      });
240    });
241
242    describe('resolveObfuscationConfigs', () => {
243      const projectConfig = {
244        obfuscationOptions: { option1: 'value1' },
245        compileHar: true
246      };
247      const logger = console;
248      const isTerser = false;
249      let newObConfigResolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
250      let testClass: ObConfigResolver & {
251        performancePrinter?: any;
252      };
253      testClass = newObConfigResolver;
254
255      it('should return a MergedConfig object when sourceObConfig is undefined', () => {
256        testClass.sourceObConfig = undefined;
257        testClass.isHarCompiled = true;
258        testClass.performancePrinter = {};
259        const result = testClass.resolveObfuscationConfigs();
260        generateConsumerObConfigFile(testClass.sourceObConfig, undefined);
261
262        expect(testClass.sourceObConfig).to.be.an.undefined;
263        expect(result).to.deep.equal(new MergedConfig());
264        expect(result).to.be.an('object');
265        expect(result).to.have.property('options');
266      });
267
268      it('should return a MergedConfig object when sourceObConfig is null', () => {
269        testClass.sourceObConfig = null;
270        testClass.isHarCompiled = true;
271        testClass.performancePrinter = {};
272        const result = testClass.resolveObfuscationConfigs();
273        generateConsumerObConfigFile(null, undefined);
274
275        expect(testClass.sourceObConfig).to.be.a.null;
276        expect(result).to.deep.equal(new MergedConfig());
277        expect(result).to.be.an('object');
278        expect(result).to.have.property('options');
279      });
280
281      it('should handle the case when sourceObConfig.selfConfig.ruleOptions.enable is false', function () {
282        testClass.sourceObConfig = {
283          selfConfig: {
284            ruleOptions: { enable: false },
285          },
286          dependencies: { libraries: [], hars: [] },
287        };
288        generateConsumerObConfigFile(testClass.sourceObConfig, undefined);
289        const result = testClass.resolveObfuscationConfigs();
290
291        expect(result).to.be.an('object');
292        expect(result).to.have.property('options');
293        expect(result.options.disableObfuscation).to.be.true;
294      });
295
296      it('should handle the case when sourceObConfig.selfConfig.ruleOptions.enable is true', function () {
297        testClass.sourceObConfig = {
298          selfConfig: {
299            ruleOptions: { enable: true },
300          },
301          dependencies: { libraries: [], hars: [] },
302        };
303        generateConsumerObConfigFile(testClass.sourceObConfig, undefined);
304        const result = testClass.resolveObfuscationConfigs();
305
306        expect(result).to.be.an('object');
307        expect(result).to.have.property('options');
308        expect(result.options.disableObfuscation).to.be.false;
309      });
310
311      it('should handle the case when enableObfuscation is false', () => {
312        const sourceObConfig = {
313          selfConfig: {
314            ruleOptions: { enable: false },
315            consumerRules: ['./test/testData/obfuscation/keepDts/obfuscation-template.txt'],
316          },
317          dependencies: { libraries: [], hars: [] },
318          obfuscationCacheDir: './test/testData/cache',
319          options: {
320            disableObfuscation: true
321          },
322          exportRulePath: '',
323          sdkApis: []
324        };
325        const isHarCompiled = true;
326        let enableObfuscation = sourceObConfig.selfConfig.ruleOptions.enable;
327        let selfConfig = new MergedConfig();
328        enableObfuscation = !selfConfig.options.disableObfuscation;
329        let needConsumerConfigs = isHarCompiled && sourceObConfig.selfConfig.consumerRules &&
330          sourceObConfig.selfConfig.consumerRules.length > 0;
331        let needDependencyConfigs = enableObfuscation || needConsumerConfigs;
332        let dependencyConfigs = new MergedConfig();
333        const dependencyMaxLength = Math.max(
334          sourceObConfig.dependencies.libraries.length,
335          sourceObConfig.dependencies.hars.length,
336        );
337        newObConfigResolver.getDependencyConfigsForTest(sourceObConfig, dependencyConfigs);
338
339        expect(needConsumerConfigs).to.be.true;
340        expect(!dependencyMaxLength).to.be.true;
341        expect(needDependencyConfigs).to.be.true;
342        expect(dependencyConfigs).to.deep.equal(new MergedConfig());
343        expect(enableObfuscation).to.be.true;
344      });
345
346      it('should handle the case when enableObfuscation is false', () => {
347        const localHarConfig = {
348          selfConfig: {
349            ruleOptions: {
350              enable: true,
351              rules: ['./test/testData/obfuscation/Configs/localHar/obfuscation-rules.txt']
352            },
353            consumerRules: [],
354            libDir: "",
355            consumerFiles: ""
356          },
357          dependencies: { libraries: [], hars: [] },
358          sdkApis: [],
359          obfuscationCacheDir: '',
360          exportRulePath: ''
361        };
362
363        const sourceObConfig = {
364          selfConfig: {
365            options: {
366              disableObfuscation: false,
367              enablePropertyObfuscation: true,
368              enableExportObfuscation: true,
369              enableToplevelObfuscation: true
370            },
371            ruleOptions: { enable: true },
372            consumerRules: ['./test/testData/obfuscation/keepDts/obfuscation-template.txt'],
373            libDir: ''
374          },
375          dependencies: { libraries: [localHarConfig.selfConfig], hars: [] },
376          obfuscationCacheDir: './test/testData/cache',
377          sdkApis: [],
378          exportRulePath: ''
379        };
380        const isHarCompiled = true;
381        let enableObfuscation = sourceObConfig.selfConfig.ruleOptions.enable;
382        let selfConfig = new MergedConfig();
383        enableObfuscation = !selfConfig.options.disableObfuscation;
384        let needConsumerConfigs = isHarCompiled && sourceObConfig.selfConfig.consumerRules &&
385          sourceObConfig.selfConfig.consumerRules.length > 0;
386        let needDependencyConfigs = enableObfuscation || needConsumerConfigs;
387        let dependencyConfigs = new MergedConfig();
388        const dependencyMaxLength = Math.max(
389          sourceObConfig.dependencies.libraries.length,
390          sourceObConfig.dependencies.hars.length,
391        );
392        const mergedConfigs = newObConfigResolver.getMergedConfigsForTest(selfConfig, dependencyConfigs);
393        newObConfigResolver.handleReservedArrayForTest(mergedConfigs);
394        let needKeepSystemApi = enableObfuscation &&
395          (mergedConfigs.options.enablePropertyObfuscation ||
396            (mergedConfigs.options.enableExportObfuscation && mergedConfigs.options.enableToplevelObfuscation));
397
398        newObConfigResolver.getDependencyConfigsForTest(sourceObConfig, dependencyConfigs);
399
400        expect(needConsumerConfigs).to.be.true;
401        expect(!dependencyMaxLength).to.be.false;
402        expect(needDependencyConfigs).to.be.true;
403        expect(dependencyConfigs).to.deep.equal(new MergedConfig());
404        expect(enableObfuscation).to.be.true;
405        expect(needKeepSystemApi).to.be.false;
406        expect(needConsumerConfigs).to.be.true;
407      });
408
409      it('should handle the case when enableObfuscation is true', () => {
410        testClass.sourceObConfig = {
411          selfConfig: {
412            ruleOptions: { enable: true },
413            consumerRules: ['./test/testData/obfuscation/keepDts/obfuscation-template.txt'],
414          },
415          dependencies: { libraries: [], hars: [] },
416          obfuscationCacheDir: './test/testData/cache',
417          options: {
418            disableObfuscation: true
419          }
420        };
421        testClass.isHarCompiled = true;
422        testClass.performancePrinter = {};
423        let enableObfuscation = testClass.sourceObConfig.selfConfig.ruleOptions.enable;
424        let selfConfig = new MergedConfig();
425        newObConfigResolver.getSelfConfigsForTest(selfConfig);
426        enableObfuscation = !selfConfig.options.disableObfuscation;
427        enableObfuscation = false;
428        let needConsumerConfigs = testClass.isHarCompiled && testClass.sourceObConfig.selfConfig.consumerRules &&
429          testClass.sourceObConfig.selfConfig.consumerRules.length > 0;
430        let needDependencyConfigs = enableObfuscation || needConsumerConfigs;
431        let dependencyConfigs = new MergedConfig();
432        const dependencyMaxLength = Math.max(
433          testClass.sourceObConfig.dependencies.libraries.length,
434          testClass.sourceObConfig.dependencies.hars.length,
435          testClass.sourceObConfig.dependencies.hsps?.length ?? 0,
436          testClass.sourceObConfig.dependencies.hspLibraries?.length ?? 0
437        );
438        newObConfigResolver.getDependencyConfigsForTest(testClass.sourceObConfig, dependencyConfigs);
439
440        expect(needConsumerConfigs).to.be.true;
441        expect(!dependencyMaxLength).to.be.true;
442        expect(needDependencyConfigs).to.be.true;
443        expect(dependencyConfigs).to.deep.equal(new MergedConfig());
444        expect(enableObfuscation).to.be.false;
445      });
446    });
447
448    describe('getSelfConfigs', () => {
449      it('should create an instance with the correct properties', () => {
450        const projectConfig = {
451          obfuscationOptions: {
452            selfConfig: {
453              ruleOptions: {
454                rules: []
455              }
456            }
457          },
458          compileHar: true
459        };
460        const isTerser = false;
461        const resolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
462
463        expect(resolver).to.be.an('object');
464        expect(resolver.sourceObConfig).to.deep.equal(projectConfig.obfuscationOptions);
465        expect(resolver.isHarCompiled).to.equal(projectConfig.compileHar);
466        expect(resolver.isTerser).to.equal(isTerser);
467      });
468
469      it('should create an instance with the correct properties', () => {
470        const projectConfig = {
471          obfuscationOptions: {
472            selfConfig: {
473              ruleOptions: {
474                rules: ['./test/ut/initialization/tempNameCache.json']
475              }
476            }
477          },
478          compileHar: true
479        };
480        const isTerser = false;
481        const resolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
482
483        expect(resolver).to.be.an('object');
484        expect(resolver.sourceObConfig).to.deep.equal(projectConfig.obfuscationOptions);
485        expect(resolver.isHarCompiled).to.equal(projectConfig.compileHar);
486        expect(resolver.isTerser).to.equal(isTerser);
487      });
488
489      it('should get self configs correctly', () => {
490        const projectConfig = {
491          obfuscationOptions: {
492            selfConfig: {
493              ruleOptions: {
494                rules: ['./test/ut/initialization/tempNameCache.json']
495              }
496            }
497          },
498          compileHar: true
499        };
500        const isTerser = false;
501        const resolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
502        const selfConfigs = new MergedConfig();
503
504        resolver.getSelfConfigsForTest(selfConfigs);
505
506        expect(resolver).to.be.an('object');
507        expect(resolver.sourceObConfig).to.deep.equal(projectConfig.obfuscationOptions);
508        expect(resolver.isHarCompiled).to.equal(projectConfig.compileHar);
509        expect(resolver.isTerser).to.equal(isTerser);
510      });
511    });
512
513    describe('getConfigByPath', () => {
514      const projectConfig = {
515        obfuscationOptions: {
516          selfConfig: {
517            ruleOptions: {
518              rules: ['./test/testData/obfuscation/filename_obf/getConfigByPath.json']
519            }
520          }
521        },
522        compileHar: true
523      };
524      let sandbox;
525      let instance;
526
527      beforeEach(() => {
528        sandbox = sinon.createSandbox();
529        instance = new ObConfigResolver(projectConfig, printObfLogger, true);
530        instance.logger = { error: sandbox.stub() };
531      });
532
533      afterEach(() => {
534        sandbox.restore();
535      });
536
537      it('should read file content and handle config content', () => {
538        const path = './test/testData/obfuscation/filename_obf/getConfigByPath.json';
539        let fileContent;
540        const expectedContent = '{"key": "value"}';
541        const configs = new MergedConfig();
542
543        fileContent = fs.readFileSync(path, 'utf-8');
544        instance.getConfigByPathForTest(path, configs);
545        instance.handleConfigContent(fileContent, configs, path);
546
547        expect(fileContent).to.equal(expectedContent);
548        expect(configs).to.be.an.instanceOf(MergedConfig);
549      });
550
551      it('should log error and throw when failed to open file', () => {
552        const path = './test/testData/obfuscation/filename_obf/non-existent-file.json';
553        const configs = new MergedConfig();
554        const stub = sinon.stub(console, 'error');
555        const errorMessage = `Failed to open ${path}. Error message: Error: ENOENT: no such file or directory, open ${path}`;
556        sandbox.stub(fs, 'readFileSync').throws(new Error(`ENOENT: no such file or directory, open ${path}`));
557        try {
558          instance.getConfigByPath(path, configs);
559        } catch (err) {
560        }
561        expect(stub.calledWith(errorMessage)).to.be.true;
562        stub.restore();
563      });
564
565      it('should log error and throw when failed to open file with hvigor errorCode', () => {
566        const path = './test/testData/obfuscation/filename_obf/non-existent-file.json';
567        const configs = new MergedConfig();
568        const stub = sinon.stub(console, 'error');
569        const errorMessage = {
570          code: '10804001',
571          description: 'ArkTS compiler Error',
572          cause: `Failed to open obfuscation config file from ${path}. Error message: Error: ENOENT: no such file or directory, open ${path}`,
573          position: path,
574          solutions: [`Please check whether ${path} exists.`],
575        };
576        instance = new ObConfigResolver(projectConfig, printObfHvigorLogger, true);
577        sandbox.stub(fs, 'readFileSync').throws(new Error(`ENOENT: no such file or directory, open ${path}`));
578        try {
579          instance.getConfigByPath(path, configs);
580        } catch (err) {
581        }
582        expect(stub.calledWith(errorMessage)).to.be.true;
583        stub.restore();
584      });
585    });
586
587    it('should return a new MergedConfig instance when sourceObConfig is not defined', function() {
588      const projectConfig = {
589        sourceObConfig: null,
590        getMergedConfig: function() {
591          let sourceObConfig = this.sourceObConfig;
592          if (!sourceObConfig) {
593            return new MergedConfig();
594          }
595        }
596      };
597
598      const result = projectConfig.getMergedConfig();
599      expect(result).to.be.an.instanceOf(MergedConfig);
600    });
601
602    describe('resolveKeepConfig', () => {
603      it('should resolve keep config correctly, starts with "!" and contains "*", not starts with "!"', () => {
604        const keepConfigs = ['!test/*/exclude.js', 'test/include.js'];
605        const configs = new MergedConfig();
606        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
607
608        newObConfigResolver.resolveKeepConfig(keepConfigs, configs, configPath);
609
610        expect(configs.excludeUniversalPaths).to.have.lengthOf(1);
611        expect(configs.keepUniversalPaths).to.have.lengthOf(0);
612        expect(configs.excludePathSet).to.have.lengthOf(0);
613        expect(configs.keepSourceOfPaths).to.have.lengthOf(0);
614      });
615
616      it('should resolve keep config correctly, starts with "!" and contains "*", not starts with "!" and "?"', () => {
617        const keepConfigs = ['!test/*/exclude.js', 'test/?/include.js'];
618        const configs = new MergedConfig();
619        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
620
621        newObConfigResolver.resolveKeepConfig(keepConfigs, configs, configPath);
622
623        expect(configs.excludeUniversalPaths).to.have.lengthOf(1);
624        expect(configs.keepUniversalPaths).to.have.lengthOf(1);
625        expect(configs.excludePathSet).to.have.lengthOf(0);
626        expect(configs.keepSourceOfPaths).to.have.lengthOf(0);
627      });
628
629      it('should resolve keep config correctly, both start with "!", contains "*" and "?"', () => {
630        const keepConfigs = ['!test/*/exclude.js', '!test/?/include.js'];
631        const configs = new MergedConfig();
632        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
633
634        newObConfigResolver.resolveKeepConfig(keepConfigs, configs, configPath);
635
636        expect(configs.excludeUniversalPaths).to.have.lengthOf(2);
637        expect(configs.keepUniversalPaths).to.have.lengthOf(0);
638        expect(configs.excludePathSet).to.have.lengthOf(0);
639        expect(configs.keepSourceOfPaths).to.have.lengthOf(0);
640      });
641
642      it('should resolve keep config correctly, not starts with "!" and contains "*" and "?"', () => {
643        const keepConfigs = ['test/*/exclude.js', 'test/?/include.js'];
644        const configs = new MergedConfig();
645        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
646
647        newObConfigResolver.resolveKeepConfig(keepConfigs, configs, configPath);
648
649        expect(configs.excludeUniversalPaths).to.have.lengthOf(0);
650        expect(configs.keepUniversalPaths).to.have.lengthOf(2);
651        expect(configs.excludePathSet).to.have.lengthOf(0);
652        expect(configs.keepSourceOfPaths).to.have.lengthOf(0);
653      });
654
655      it('should resolve keep config correctly, starts with "!", not starts with "!" and contains "*"', () => {
656        const keepConfigs = ['!test/exclude.js', 'test/*/include.js'];
657        const configs = new MergedConfig();
658        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
659
660        newObConfigResolver.resolveKeepConfig(keepConfigs, configs, configPath);
661
662        expect(configs.excludeUniversalPaths).to.have.lengthOf(0);
663        expect(configs.keepUniversalPaths).to.have.lengthOf(1);
664        expect(configs.excludePathSet).to.have.lengthOf(1);
665        expect(configs.keepSourceOfPaths).to.have.lengthOf(0);
666      });
667
668      it('should resolve keep config correctly, starts with "!" and not starts with "!"', () => {
669        const keepConfigs = ['!test/exclude.js', 'test/include.js'];
670        const configs = new MergedConfig();
671        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
672
673        newObConfigResolver.resolveKeepConfig(keepConfigs, configs, configPath);
674
675        expect(configs.excludeUniversalPaths).to.have.lengthOf(0);
676        expect(configs.keepUniversalPaths).to.have.lengthOf(0);
677        expect(configs.excludePathSet).to.have.lengthOf(1);
678        expect(configs.keepSourceOfPaths).to.have.lengthOf(0);
679      });
680
681      it('should resolve keep config correctly, both start with "!"', () => {
682        const keepConfigs = ['!test/exclude.js', '!test/include.js'];
683        const configs = new MergedConfig();
684        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
685
686        newObConfigResolver.resolveKeepConfig(keepConfigs, configs, configPath);
687
688        expect(configs.excludeUniversalPaths).to.have.lengthOf(0);
689        expect(configs.keepUniversalPaths).to.have.lengthOf(0);
690        expect(configs.excludePathSet).to.have.lengthOf(2);
691        expect(configs.keepSourceOfPaths).to.have.lengthOf(0);
692      });
693    });
694
695    describe('resolvePath', () => {
696      it('should return the absolute path if token is already an absolute path', () => {
697        const configPath = '/home/user/config.json';
698        const token = '/home/user/data.txt';
699        const result = newObConfigResolver.resolvePathForTest(configPath, token);
700        expect(result).to.equal(token);
701      });
702
703      it('should resolve the relative path based on the config file directory', () => {
704        const configPath = '/home/user/config.json';
705        const token = 'data.txt';
706        const expectedResult = '/home/user/data.txt';
707        const result = newObConfigResolver.resolvePathForTest(configPath, token);
708        expect(result).to.equal(expectedResult);
709      });
710    });
711
712    describe('getTokenType', () => {
713      it('should return the correct OptionType for each token', () => {
714        const tokens = [
715          ObConfigResolver.KEEP_DTS,
716          ObConfigResolver.KEEP_GLOBAL_NAME,
717          ObConfigResolver.KEEP_PROPERTY_NAME,
718          ObConfigResolver.KEEP_FILE_NAME,
719          ObConfigResolver.KEEP_COMMENTS,
720          ObConfigResolver.DISABLE_OBFUSCATION,
721          ObConfigResolver.ENABLE_PROPERTY_OBFUSCATION,
722          ObConfigResolver.ENABLE_STRING_PROPERTY_OBFUSCATION,
723          ObConfigResolver.ENABLE_TOPLEVEL_OBFUSCATION,
724          ObConfigResolver.ENABLE_FILENAME_OBFUSCATION,
725          ObConfigResolver.ENABLE_EXPORT_OBFUSCATION,
726          ObConfigResolver.ENABLE_LIB_OBFUSCATION_OPTIONS,
727          ObConfigResolver.REMOVE_COMMENTS,
728          ObConfigResolver.COMPACT,
729          ObConfigResolver.REMOVE_LOG,
730          ObConfigResolver.PRINT_NAMECACHE,
731          ObConfigResolver.PRINT_KEPT_NAMES,
732          ObConfigResolver.APPLY_NAMECACHE,
733          ObConfigResolver.KEEP,
734          ObConfigResolver.EXTRA_OPTIONS,
735          ObConfigResolver.STRIP_LANGUAGE_DEFAULT,
736          ObConfigResolver.STRIP_SYSTEM_API_ARGS,
737          'unknown_token'
738        ];
739
740        const expectedResults = [
741          OptionTypeForTest.KEEP_DTS,
742          OptionTypeForTest.KEEP_GLOBAL_NAME,
743          OptionTypeForTest.KEEP_PROPERTY_NAME,
744          OptionTypeForTest.KEEP_FILE_NAME,
745          OptionTypeForTest.KEEP_COMMENTS,
746          OptionTypeForTest.DISABLE_OBFUSCATION,
747          OptionTypeForTest.ENABLE_PROPERTY_OBFUSCATION,
748          OptionTypeForTest.ENABLE_STRING_PROPERTY_OBFUSCATION,
749          OptionTypeForTest.ENABLE_TOPLEVEL_OBFUSCATION,
750          OptionTypeForTest.ENABLE_FILENAME_OBFUSCATION,
751          OptionTypeForTest.ENABLE_EXPORT_OBFUSCATION,
752          OptionTypeForTest.ENABLE_LIB_OBFUSCATION_OPTIONS,
753          OptionTypeForTest.REMOVE_COMMENTS,
754          OptionTypeForTest.COMPACT,
755          OptionTypeForTest.REMOVE_LOG,
756          OptionTypeForTest.PRINT_NAMECACHE,
757          OptionTypeForTest.PRINT_KEPT_NAMES,
758          OptionTypeForTest.APPLY_NAMECACHE,
759          OptionTypeForTest.KEEP,
760          OptionTypeForTest.EXTRA_OPTIONS,
761          OptionTypeForTest.STRIP_LANGUAGE_DEFAULT,
762          OptionTypeForTest.STRIP_SYSTEM_API_ARGS,
763          OptionTypeForTest.NONE
764        ];
765
766        for (let i = 0; i < tokens.length; i++) {
767          const result = newObConfigResolver.getTokenTypeForTest(tokens[i]);
768          expect(result).to.equal(expectedResults[i]);
769        }
770      });
771    });
772
773    describe('handleConfigContent', () => {
774      it('should handle config content correctly', () => {
775        const configs: MergedConfig = new MergedConfig();
776        configs.options = new ObOptionsForTest();
777
778        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
779        const data = `
780          #This is a comment
781          -none,
782          -keep obfuscation-template.txt,
783          -keep-dts,
784          -keep-global-name,
785          -keep-property-name,
786          -keep-file-name,
787          -keep-comments,
788          -disable-obfuscation,
789          -enable-property-obfuscation,
790          -enable-string-property-obfuscation,
791          -enable-toplevel-obfuscation,
792          -enable-filename-obfuscation,
793          -enable-export-obfuscation,
794          -enable-lib-obfuscation-options,
795          -use-keep-in-source,
796          -extra-options strip-language-default,
797          -extra-options strip-system-api-args,
798          -keep-parameter-names
799          -remove-comments,
800          -compact,
801          -remove-log,
802          -print-namecache obfuscation-template.txt,
803          -print-kept-names,
804          -apply-namecache obfuscation-template.txt
805        `;
806
807        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
808
809        expect(configs.options.disableObfuscation).to.be.true;
810        expect(configs.options.enablePropertyObfuscation).to.be.true;
811        expect(configs.options.enableStringPropertyObfuscation).to.be.true;
812        expect(configs.options.enableToplevelObfuscation).to.be.true;
813        expect(configs.options.removeComments).to.be.true;
814        expect(configs.options.enableFileNameObfuscation).to.be.true;
815        expect(configs.options.enableExportObfuscation).to.be.true;
816        expect(configs.options.enableLibObfuscationOptions).to.be.true;
817        expect(configs.options.enableAtKeep).to.be.true;
818        expect(configs.options.compact).to.be.true;
819        expect(configs.options.removeLog).to.be.true;
820        expect(configs.options.stripLanguageDefault).to.be.true;
821        expect(configs.options.stripSystemApiArgs).to.be.true;
822        expect(configs.options.keepParameterNames).to.be.true;
823      });
824
825      it('should handle config content correctly when diffenent combinations use line break splitting', () => {
826        const configs: MergedConfig = new MergedConfig();
827        configs.options = new ObOptionsForTest();
828
829        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
830        const data = `
831          #This is a comment
832          -extra-options
833          strip-language-default
834          -extra-options
835          strip-system-api-args
836        `;
837
838        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
839
840        expect(configs.options.stripLanguageDefault).to.be.true;
841        expect(configs.options.stripSystemApiArgs).to.be.true;
842      });
843
844      it('should handle config content correctly when diffenent combinations use line break splitting', () => {
845        const configs: MergedConfig = new MergedConfig();
846        configs.options = new ObOptionsForTest();
847
848        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
849        const data = `
850          #This is a comment
851          -extra-options strip-language-default
852          -extra-options strip-system-api-args
853        `;
854
855        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
856
857        expect(configs.options.stripLanguageDefault).to.be.true;
858        expect(configs.options.stripSystemApiArgs).to.be.true;
859      });
860
861      it('should handle config content correctly when diffenent combinations use space separation', () => {
862        const configs: MergedConfig = new MergedConfig();
863        configs.options = new ObOptionsForTest();
864
865        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
866        const data = `
867          #This is a comment
868          -extra-options strip-language-default -extra-options strip-system-api-args
869        `;
870
871        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
872
873        expect(configs.options.stripLanguageDefault).to.be.true;
874        expect(configs.options.stripSystemApiArgs).to.be.true;
875      });
876
877      it('should handle config content correctly when diffenent combinations only use one "-extra-options"', () => {
878        const configs: MergedConfig = new MergedConfig();
879        configs.options = new ObOptionsForTest();
880
881        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
882        const data = `
883          #This is a comment
884          -extra-options strip-language-default, strip-system-api-args
885        `;
886
887        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
888
889        expect(configs.options.stripLanguageDefault).to.be.true;
890        expect(configs.options.stripSystemApiArgs).to.be.true;
891      });
892
893      it('should handle config content correctly when no "-extra-options"', () => {
894        const configs: MergedConfig = new MergedConfig();
895        configs.options = new ObOptionsForTest();
896
897        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
898        const data = `
899          #This is a comment
900          strip-language-default, strip-system-api-args
901        `;
902
903        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
904
905        expect(configs.options.stripLanguageDefault).to.be.false;
906        expect(configs.options.stripSystemApiArgs).to.be.false;
907      });
908
909      it('should handle config content correctly when have invalid token between "-extra-options" and "strip-language-default"', () => {
910        const configs: MergedConfig = new MergedConfig();
911        configs.options = new ObOptionsForTest();
912
913        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
914        const data = `
915          #This is a comment
916          -extra-options
917          invalid-token
918          strip-system-api-args
919          strip-language-default
920        `;
921
922        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
923
924        expect(configs.options.stripLanguageDefault).to.be.false;
925        expect(configs.options.stripSystemApiArgs).to.be.false;
926      });
927
928      it('should handle config content correctly when have valid token between "-extra-options" and "strip-language-default"', () => {
929        const configs: MergedConfig = new MergedConfig();
930        configs.options = new ObOptionsForTest();
931
932        const configPath = './test/testData/obfuscation/keepDts/obfuscation-template.txt';
933        const data = `
934          #This is a comment
935          -extra-options
936          -enable-property-obfuscation
937          strip-language-default
938          strip-system-api-args
939        `;
940
941        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
942
943        expect(configs.options.enablePropertyObfuscation).to.be.true;
944        expect(configs.options.stripLanguageDefault).to.be.false;
945        expect(configs.options.stripSystemApiArgs).to.be.false;
946      });
947
948      it('should handle config content correctly when enable lib obfuscation options', () => {
949        const configs: MergedConfig = new MergedConfig();
950        configs.options = new ObOptionsForTest();
951
952        const configPath = './test/testData/obfuscation/enable_lib_obfuscation_options/obfuscation-rule.txt';
953        const data = fs.readFileSync(configPath, 'utf-8');
954
955        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
956
957        expect(configs.options.enableLibObfuscationOptions).to.be.true;
958      });
959
960      it('should handle config correctly when enable bytecode obfuscation options', () => {
961        const configs: MergedConfig = new MergedConfig();
962        configs.options = new ObOptionsForTest();
963
964        const configPath = './test/testData/obfuscation/enable_lib_obfuscation_options/obfuscation-rule.txt';
965        const data = `
966        -enable-bytecode-obfuscation
967        -enable-bytecode-obfuscation-debugging
968        -enable-bytecode-obfuscation-enhanced
969        -enable-bytecode-obfuscation-arkui
970      `;
971        newObConfigResolver.handleConfigContentForTest(data, configs, configPath);
972        expect(configs.options.bytecodeObf.enable).to.be.true;
973        expect(configs.options.bytecodeObf.debugging).to.be.true;
974        expect(configs.options.bytecodeObf.enhanced).to.be.true;
975        expect(configs.options.bytecodeObf.obfArkUI).to.be.true;
976      });
977    });
978
979    describe('1: test Api collectSystemApiWhitelist', function() {
980      it('1-1: test collectSystemApiWhitelist: -enable-property-obfuscation', function () {
981        let obfuscationCacheDir = path.join(OBFUSCATE_TESTDATA_DIR, 'property');
982        let obfuscationOptions = {
983          'selfConfig': {
984            'ruleOptions': {
985              'enable': true,
986              'rules': [
987                path.join(OBFUSCATE_TESTDATA_DIR, 'property/property.txt')
988              ]
989            },
990            'consumerRules': [],
991          },
992          'dependencies': {
993            'libraries': [],
994            'hars': []
995          },
996          'obfuscationCacheDir': obfuscationCacheDir,
997          'sdkApis': [
998            path.join(OBFUSCATE_TESTDATA_DIR, 'system_api.d.ts')
999          ]
1000        };
1001        let projectConfig = {
1002          obfuscationOptions,
1003          compileHar: false
1004        };
1005        const obConfig: ObConfigResolver =  new ObConfigResolver(projectConfig, undefined);
1006        obConfig.resolveObfuscationConfigs();
1007        const reservedSdkApiForProp = UnobfuscationCollections.reservedSdkApiForProp;
1008        const reservedSdkApiForGlobal = UnobfuscationCollections.reservedSdkApiForGlobal;
1009        const reservedSdkApiForLocal = UnobfuscationCollections.reservedSdkApiForLocal;
1010
1011        expect(reservedSdkApiForProp.size == 12).to.be.true;
1012        expect(reservedSdkApiForProp.has('TestClass')).to.be.true;
1013        expect(reservedSdkApiForProp.has('para1')).to.be.true;
1014        expect(reservedSdkApiForProp.has('para2')).to.be.true;
1015        expect(reservedSdkApiForProp.has('foo')).to.be.true;
1016        expect(reservedSdkApiForProp.has('TestFunction')).to.be.true;
1017        expect(reservedSdkApiForProp.has('funcPara1')).to.be.true;
1018        expect(reservedSdkApiForProp.has('funcPara2')).to.be.true;
1019        expect(reservedSdkApiForProp.has('ns')).to.be.true;
1020        expect(reservedSdkApiForProp.has('NavigationBuilderRegister')).to.be.true;
1021        expect(reservedSdkApiForProp.has('ViewV2')).to.be.true;
1022        expect(reservedSdkApiForProp.has('initParam')).to.be.true;
1023        expect(reservedSdkApiForProp.has('updateParam')).to.be.true;
1024        expect(reservedSdkApiForProp.has('NavigationBuilderRegister')).to.be.true;
1025        expect(reservedSdkApiForProp.has('__Recycle__')).to.be.false;
1026        expect(reservedSdkApiForGlobal.size === 0).to.be.true;
1027        expect(reservedSdkApiForLocal.size === 8).to.be.true;
1028        UnobfuscationCollections.clear();
1029
1030        let systemApiPath = obfuscationCacheDir + '/systemApiCache.json';
1031        const data = fs.readFileSync(systemApiPath, 'utf8');
1032        const systemApiContent = JSON.parse(data);
1033
1034        expect(systemApiContent.ReservedPropertyNames.length == 12).to.be.true;
1035        expect(systemApiContent.ReservedPropertyNames.includes('TestClass')).to.be.true;
1036        expect(systemApiContent.ReservedPropertyNames.includes('para1')).to.be.true;
1037        expect(systemApiContent.ReservedPropertyNames.includes('para2')).to.be.true;
1038        expect(systemApiContent.ReservedPropertyNames.includes('foo')).to.be.true;
1039        expect(systemApiContent.ReservedPropertyNames.includes('TestFunction')).to.be.true;
1040        expect(systemApiContent.ReservedPropertyNames.includes('funcPara1')).to.be.true;
1041        expect(systemApiContent.ReservedPropertyNames.includes('funcPara2')).to.be.true;
1042        expect(systemApiContent.ReservedPropertyNames.includes('ns')).to.be.true;
1043        expect(systemApiContent.ReservedPropertyNames.includes('NavigationBuilderRegister')).to.be.true;
1044        expect(systemApiContent.ReservedPropertyNames.includes('ViewV2')).to.be.true;
1045        expect(systemApiContent.ReservedPropertyNames.includes('initParam')).to.be.true;
1046        expect(systemApiContent.ReservedPropertyNames.includes('updateParam')).to.be.true;
1047        expect(systemApiContent.ReservedPropertyNames.includes('NavigationBuilderRegister')).to.be.true;
1048        expect(systemApiContent.ReservedPropertyNames.includes('__Recycle__')).to.be.false;
1049        expect(systemApiContent.ReservedGlobalNames === undefined).to.be.true;
1050        expect(systemApiContent.ReservedLocalNames.size === 8).to.be.false;
1051
1052        fs.unlinkSync(systemApiPath);
1053      });
1054
1055      it('1-2: test collectSystemApiWhitelist: -enable-export-obfuscation', function () {
1056        let obfuscationCacheDir = path.join(OBFUSCATE_TESTDATA_DIR, 'export');
1057        let obfuscationOptions = {
1058          'selfConfig': {
1059            'ruleOptions': {
1060              'enable': true,
1061              'rules': [
1062                path.join(OBFUSCATE_TESTDATA_DIR, 'export/export.txt')
1063              ]
1064            },
1065            'consumerRules': [],
1066          },
1067          'dependencies': {
1068            'libraries': [],
1069            'hars': []
1070          },
1071          'obfuscationCacheDir': obfuscationCacheDir,
1072          'sdkApis': [
1073            path.join(OBFUSCATE_TESTDATA_DIR, 'system_api.d.ts')
1074          ]
1075        };
1076        let projectConfig = {
1077          obfuscationOptions,
1078          compileHar: false
1079        };
1080        const obConfig: ObConfigResolver =  new ObConfigResolver(projectConfig, undefined);
1081        obConfig.resolveObfuscationConfigs();
1082        const reservedSdkApiForProp = UnobfuscationCollections.reservedSdkApiForProp;
1083        const reservedSdkApiForGlobal = UnobfuscationCollections.reservedSdkApiForGlobal;
1084
1085        expect(reservedSdkApiForProp.size == 0).to.be.true;
1086        expect(reservedSdkApiForGlobal.size == 0).to.be.true;
1087        UnobfuscationCollections.clear();
1088
1089        let systemApiPath = obfuscationCacheDir + '/systemApiCache.json';
1090        const noSystemApi = fs.existsSync(systemApiPath);
1091
1092        expect(noSystemApi).to.be.false;
1093      });
1094
1095      it('1-3: test collectSystemApiWhitelist: -enable-export-obfuscation -enable-toplevel-obfuscation', function () {
1096        let obfuscationCacheDir = path.join(OBFUSCATE_TESTDATA_DIR, 'export_toplevel');
1097        let obfuscationOptions = {
1098          'selfConfig': {
1099            'ruleOptions': {
1100              'enable': true,
1101              'rules': [
1102                path.join(OBFUSCATE_TESTDATA_DIR, 'export_toplevel/export_toplevel.txt')
1103              ]
1104            },
1105            'consumerRules': [],
1106          },
1107          'dependencies': {
1108            'libraries': [],
1109            'hars': []
1110          },
1111          'obfuscationCacheDir': obfuscationCacheDir,
1112          'sdkApis': [
1113            path.join(OBFUSCATE_TESTDATA_DIR, 'system_api.d.ts')
1114          ]
1115        };
1116        let projectConfig = {
1117          obfuscationOptions,
1118          compileHar: false
1119        };
1120        const obConfig: ObConfigResolver =  new ObConfigResolver(projectConfig, undefined);
1121        obConfig.resolveObfuscationConfigs();
1122        const reservedSdkApiForProp = UnobfuscationCollections.reservedSdkApiForProp;
1123        const reservedSdkApiForGlobal = UnobfuscationCollections.reservedSdkApiForGlobal;
1124
1125        expect(reservedSdkApiForProp.size == 0).to.be.true;
1126        expect(reservedSdkApiForGlobal.size == 3).to.be.true;
1127        expect(reservedSdkApiForGlobal.has('TestClass')).to.be.true;
1128        expect(reservedSdkApiForGlobal.has('TestFunction')).to.be.true;
1129        expect(reservedSdkApiForGlobal.has('ns')).to.be.true;
1130        UnobfuscationCollections.clear();
1131
1132        let systemApiPath = obfuscationCacheDir + '/systemApiCache.json';
1133        const data = fs.readFileSync(systemApiPath, 'utf8');
1134        const systemApiContent = JSON.parse(data);
1135
1136        expect(systemApiContent.ReservedPropertyNames == undefined).to.be.true;
1137        expect(systemApiContent.ReservedGlobalNames.length == 3).to.be.true;
1138        expect(systemApiContent.ReservedGlobalNames.includes('TestClass')).to.be.true;
1139        expect(systemApiContent.ReservedGlobalNames.includes('TestFunction')).to.be.true;
1140        expect(systemApiContent.ReservedGlobalNames.includes('ns')).to.be.true;
1141
1142        fs.unlinkSync(systemApiPath);
1143      });
1144
1145      it('1-4: test collectSystemApiWhitelist: system api when -enable-property-obfuscation and -extra-options strip-system-api-args', function () {
1146        let obfuscationCacheDir = path.join(OBFUSCATE_TESTDATA_DIR, 'system_api_optimize');
1147        let obfuscationOptions = {
1148          'selfConfig': {
1149            'ruleOptions': {
1150              'enable': true,
1151              'rules': [
1152                path.join(OBFUSCATE_TESTDATA_DIR, 'system_api_optimize/system_api_optimize.txt')
1153              ]
1154            },
1155            'consumerRules': [],
1156          },
1157          'dependencies': {
1158            'libraries': [],
1159            'hars': []
1160          },
1161          'obfuscationCacheDir': obfuscationCacheDir,
1162          'sdkApis': [
1163            path.join(OBFUSCATE_TESTDATA_DIR, 'system_api.d.ts')
1164          ]
1165        };
1166        let projectConfig = {
1167          obfuscationOptions,
1168          compileHar: false
1169        };
1170        const obConfig: ObConfigResolver =  new ObConfigResolver(projectConfig, undefined);
1171        obConfig.resolveObfuscationConfigs();
1172        const reservedSdkApiForProp = UnobfuscationCollections.reservedSdkApiForProp;
1173        const reservedSdkApiForGlobal = UnobfuscationCollections.reservedSdkApiForGlobal;
1174        const reservedSdkApiForLocal = UnobfuscationCollections.reservedSdkApiForLocal;
1175
1176        expect(reservedSdkApiForProp.has('TestClass')).to.be.true;
1177        expect(reservedSdkApiForProp.has('para1')).to.be.true;
1178        expect(reservedSdkApiForProp.has('para2')).to.be.true;
1179        expect(reservedSdkApiForProp.has('foo')).to.be.true;
1180        expect(reservedSdkApiForProp.has('TestFunction')).to.be.true;
1181        expect(reservedSdkApiForProp.has('funcPara1')).to.be.false;
1182        expect(reservedSdkApiForProp.has('funcPara2')).to.be.false;
1183        expect(reservedSdkApiForProp.has('ns')).to.be.true;
1184        expect(reservedSdkApiForProp.has('NavigationBuilderRegister')).to.be.true;
1185        expect(reservedSdkApiForProp.has('__Recycle__')).to.be.true;
1186        expect(reservedSdkApiForGlobal.size == 0).to.be.true;
1187        expect(reservedSdkApiForLocal.size == 0).to.be.true;
1188        UnobfuscationCollections.clear();
1189
1190        let systemApiPath = obfuscationCacheDir + '/systemApiCache.json';
1191        const data = fs.readFileSync(systemApiPath, 'utf8');
1192        const systemApiContent = JSON.parse(data);
1193
1194        expect(systemApiContent.ReservedPropertyNames.includes('TestClass')).to.be.true;
1195        expect(systemApiContent.ReservedPropertyNames.includes('para1')).to.be.true;
1196        expect(systemApiContent.ReservedPropertyNames.includes('para2')).to.be.true;
1197        expect(systemApiContent.ReservedPropertyNames.includes('foo')).to.be.true;
1198        expect(systemApiContent.ReservedPropertyNames.includes('TestFunction')).to.be.true;
1199        expect(systemApiContent.ReservedPropertyNames.includes('funcPara1')).to.be.false;
1200        expect(systemApiContent.ReservedPropertyNames.includes('funcPara2')).to.be.false;
1201        expect(systemApiContent.ReservedPropertyNames.includes('ns')).to.be.true;
1202        expect(systemApiContent.ReservedPropertyNames.includes('NavigationBuilderRegister')).to.be.true;
1203        expect(systemApiContent.ReservedPropertyNames.includes('__Recycle__')).to.be.true;
1204        expect(systemApiContent.ReservedGlobalNames === undefined).to.be.true;
1205        expect(systemApiContent.ReservedLocalNames === undefined).to.be.true;
1206
1207        fs.unlinkSync(systemApiPath);
1208      });
1209
1210      it('1-5: test collectSystemApiWhitelist: -enable-bytecode-obfuscation', function () {
1211        let obfuscationCacheDir = path.join(OBFUSCATE_TESTDATA_DIR, 'bytecode_obfuscation');
1212        let obfuscationOptions = {
1213          'selfConfig': {
1214            'ruleOptions': {
1215              'enable': true,
1216              'rules': [
1217                path.join(OBFUSCATE_TESTDATA_DIR, 'bytecode_obfuscation/bytecode_obfuscation.txt')
1218              ]
1219            },
1220            'consumerRules': [],
1221          },
1222          'dependencies': {
1223            'libraries': [],
1224            'hars': []
1225          },
1226          'obfuscationCacheDir': obfuscationCacheDir,
1227          'sdkApis': [
1228            path.join(OBFUSCATE_TESTDATA_DIR, 'system_api.d.ts')
1229          ]
1230        };
1231        let projectConfig = {
1232          obfuscationOptions,
1233          compileHar: false
1234        };
1235        const obConfig: ObConfigResolver =  new ObConfigResolver(projectConfig, undefined);
1236        obConfig.resolveObfuscationConfigs();
1237        const reservedSdkApiForProp = UnobfuscationCollections.reservedSdkApiForProp;
1238        const reservedSdkApiForGlobal = UnobfuscationCollections.reservedSdkApiForGlobal;
1239        const reservedSdkApiForLocal = UnobfuscationCollections.reservedSdkApiForLocal;
1240
1241        expect(reservedSdkApiForProp.size == 12).to.be.true;
1242        expect(reservedSdkApiForGlobal.size == 3).to.be.true;
1243        expect(reservedSdkApiForLocal.size == 8).to.be.true;
1244        UnobfuscationCollections.clear();
1245
1246        let systemApiPath = obfuscationCacheDir + '/systemApiCache.json';
1247        const data = fs.readFileSync(systemApiPath, 'utf8');
1248        const systemApiContent = JSON.parse(data);
1249
1250        expect(systemApiContent.ReservedLocalNames.length == 8).to.be.true;
1251        expect(systemApiContent.ReservedPropertyNames.length == 12).to.be.true;
1252        expect(systemApiContent.ReservedGlobalNames.length == 3).to.be.true;
1253        fs.unlinkSync(systemApiPath);
1254      });
1255    });
1256  });
1257
1258  describe('getMergedConfigs', function() {
1259    it('should merge all configs', () => {
1260      const config1 = new MergedConfig();
1261      config1.options.enableLibObfuscationOptions = true;
1262
1263      const config2 = new MergedConfig();
1264      config2.options.enablePropertyObfuscation = true;
1265      config2.options.enableStringPropertyObfuscation = true;
1266      config2.options.enableToplevelObfuscation = true;
1267      config2.options.compact = true;
1268      config2.options.removeLog = true;
1269      config2.reservedPropertyNames = ['prop2'];
1270      config2.reservedGlobalNames = ['global2'];
1271      config2.keepComments = ['comment2'];
1272      config2.excludePathSet.add('path2');
1273
1274      const projectConfig = {
1275        obfuscationOptions: { option1: 'value1' },
1276        compileHar: false
1277      };
1278      const logger = console;
1279      const isTerser = false;
1280      let newObConfigResolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
1281      const res: MergedConfig = newObConfigResolver.getMergedConfigsForTest(config1, config2);
1282
1283      expect(res.options.enablePropertyObfuscation).to.be.true;
1284      expect(res.options.enableStringPropertyObfuscation).to.be.true;
1285      expect(res.options.enableToplevelObfuscation).to.be.true;
1286      expect(res.options.compact).to.be.true;
1287      expect(res.options.removeLog).to.be.true;
1288      expect(res.reservedPropertyNames).to.deep.equal(['prop2']);
1289      expect(res.reservedGlobalNames).to.deep.equal(['global2']);
1290      expect(res.keepComments).to.deep.equal(['comment2']);
1291      expect(res.excludePathSet).to.deep.equal(new Set(['path2']));
1292    });
1293
1294    it('should merge only keep configs', () => {
1295      const config1 = new MergedConfig();
1296      config1.options.enableLibObfuscationOptions = false;
1297
1298      const config2 = new MergedConfig();
1299      config2.options.enablePropertyObfuscation = true;
1300      config2.options.enableStringPropertyObfuscation = true;
1301      config2.options.enableToplevelObfuscation = true;
1302      config2.options.compact = true;
1303      config2.options.removeLog = true;
1304      config2.reservedPropertyNames = ['prop2'];
1305      config2.reservedGlobalNames = ['global2'];
1306      config2.keepComments = ['comment2'];
1307      config2.excludePathSet.add('path2');
1308
1309      const projectConfig = {
1310        obfuscationOptions: { option1: 'value1' },
1311        compileHar: false
1312      };
1313      const logger = console;
1314      const isTerser = false;
1315      let newObConfigResolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
1316      const res: MergedConfig = newObConfigResolver.getMergedConfigsForTest(config1, config2);
1317
1318      expect(res.options.enablePropertyObfuscation).to.be.false;
1319      expect(res.options.enableStringPropertyObfuscation).to.be.false;
1320      expect(res.options.enableToplevelObfuscation).to.be.false;
1321      expect(res.options.compact).to.be.false;
1322      expect(res.options.removeLog).to.be.false;
1323      expect(res.reservedPropertyNames).to.deep.equal(['prop2']);
1324      expect(res.reservedGlobalNames).to.deep.equal(['global2']);
1325      expect(res.keepComments).to.deep.equal(['comment2']);
1326      expect(res.excludePathSet).to.deep.equal(new Set(['path2']));
1327    });
1328  });
1329
1330  describe('genConsumerConfigFilesForTest', function (){
1331    it('should merge all configs: compileHar is true', () => {
1332      const config1 = new MergedConfig();
1333      config1.options.enableLibObfuscationOptions = true;
1334
1335      const config2 = new MergedConfig();
1336      config2.options.enablePropertyObfuscation = true;
1337      config2.options.enableStringPropertyObfuscation = true;
1338      config2.options.enableToplevelObfuscation = true;
1339      config2.options.compact = true;
1340      config2.options.removeLog = true;
1341      config2.reservedPropertyNames = ['prop2'];
1342      config2.reservedGlobalNames = ['global2'];
1343      config2.keepComments = ['comment2'];
1344      config2.excludePathSet.add('path2');
1345
1346      const projectConfig = {
1347        obfuscationOptions: { option1: 'value1' },
1348        compileHar: true
1349      };
1350      const logger = console;
1351      const isTerser = false;
1352      let newObConfigResolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
1353      const sourceObConfig: SourceObConfig = {
1354        selfConfig: {} as Obfuscation,
1355        sdkApis: [],
1356        obfuscationCacheDir: '',
1357        exportRulePath: './test/ut/initialization/obfuscation.txt',
1358        dependencies: {
1359          libraries: [],
1360          hars: [],
1361          hsps: [],
1362          hspLibraries: [],
1363        },
1364      };
1365      newObConfigResolver.genConsumerConfigFilesForTest(sourceObConfig, config1, config2);
1366
1367      let res: string = fs.readFileSync(sourceObConfig.exportRulePath, 'utf-8');
1368      expect(res.indexOf('-enable-lib-obfuscation-options') === -1).to.be.true;
1369      expect(res.indexOf('-enable-property-obfuscation') !== -1).to.be.true;
1370      expect(res.indexOf('-enable-string-property-obfuscation') !== -1).to.be.true;
1371      expect(res.indexOf('-enable-toplevel-obfuscation') !== -1).to.be.true;
1372      expect(res.indexOf('-compact') !== -1).to.be.true;
1373      expect(res.indexOf('-remove-log') !== -1).to.be.true;
1374      expect(res.indexOf('-keep-global-name') !== -1).to.be.true;
1375      expect(res.indexOf('global2') !== -1).to.be.true;
1376      expect(res.indexOf('-keep-property-name') !== -1).to.be.true;
1377      expect(res.indexOf('prop2') !== -1).to.be.true;
1378
1379      fs.unlinkSync(sourceObConfig.exportRulePath);
1380    });
1381
1382    it('should merge all configs: compileHar is false', () => {
1383      const config1 = new MergedConfig();
1384      config1.options.enableLibObfuscationOptions = false;
1385
1386      const config2 = new MergedConfig();
1387      config2.options.enablePropertyObfuscation = true;
1388      config2.options.enableStringPropertyObfuscation = true;
1389      config2.options.enableToplevelObfuscation = true;
1390      config2.options.compact = true;
1391      config2.options.removeLog = true;
1392      config2.reservedPropertyNames = ['prop2'];
1393      config2.reservedGlobalNames = ['global2'];
1394      config2.keepComments = ['comment2'];
1395      config2.excludePathSet.add('path2');
1396
1397      const projectConfig = {
1398        obfuscationOptions: { option1: 'value1' },
1399        compileHar: false
1400      };
1401      const logger = console;
1402      const isTerser = false;
1403      let newObConfigResolver = new ObConfigResolver(projectConfig, printObfLogger, isTerser);
1404      const sourceObConfig: SourceObConfig = {
1405        selfConfig: {} as Obfuscation,
1406        sdkApis: [],
1407        obfuscationCacheDir: '',
1408        exportRulePath: './test/ut/initialization/obfuscation.txt',
1409        dependencies: {
1410          libraries: [],
1411          hars: [],
1412          hsps: [],
1413          hspLibraries: [],
1414        },
1415      };
1416      newObConfigResolver.genConsumerConfigFilesForTest(sourceObConfig, config1, config2);
1417
1418      let res: string = fs.readFileSync(sourceObConfig.exportRulePath, 'utf-8');
1419
1420      expect(res.indexOf('-enable-lib-obfuscation-options') === -1).to.be.true;
1421      expect(res.indexOf('-enable-property-obfuscation') === -1).to.be.true;
1422      expect(res.indexOf('-enable-string-property-obfuscation') === -1).to.be.true;
1423      expect(res.indexOf('-enable-toplevel-obfuscation') === -1).to.be.true;
1424      expect(res.indexOf('-compact') === -1).to.be.true;
1425      expect(res.indexOf('-remove-log') === -1).to.be.true;
1426      expect(res.indexOf('-keep-global-name') === -1).to.be.true;
1427      expect(res.indexOf('global2') === -1).to.be.true;
1428      expect(res.indexOf('-keep-property-name') === -1).to.be.true;
1429      expect(res.indexOf('prop2') === -1).to.be.true;
1430
1431      fs.unlinkSync(sourceObConfig.exportRulePath);
1432    });
1433  });
1434
1435  describe('collectResevedFileNameInIDEConfig', () => {
1436    let collectPathReservedStringStub;
1437
1438    beforeEach(function() {
1439      collectPathReservedStringStub = sinon.stub(FileUtils, 'collectPathReservedString');
1440      collectPathReservedStringStub.callsFake((filePath, reservedArray) => reservedArray.push(filePath));
1441    });
1442
1443    afterEach(function() {
1444      collectPathReservedStringStub.restore();
1445      projectConfig.compileShared = false;
1446      projectConfig.byteCodeHar = false;
1447      projectConfig.aceModuleJsonPath = '';
1448    });
1449
1450    const ohPackagePath = './test/ut/initialization/testOhPackagePath.json';
1451    let projectConfig = {
1452      aceModuleJsonPath: '',
1453      projectPath: 'path/to/project',
1454      cachePath: 'path/to/cache',
1455      compileShared: false,
1456      byteCodeHar: false,
1457      aceModuleBuild: 'path/to/build',
1458    }
1459    const entryArray = ['path/to/entry1', 'path/to/entry2'];
1460    const modulePathMap = {
1461      module1: 'path/to/module1',
1462      module2: 'path/to/module2',
1463    };
1464
1465    it('should collect reserved file names from entryArray and projectConfig', () => {
1466      const result = collectResevedFileNameInIDEConfig('', projectConfig, undefined, entryArray);
1467      expect(result).to.deep.equal(['path/to/entry1', 'path/to/entry2','path/to/project','path/to/cache']);
1468    });
1469    it('should collect reserved file names from modulePathMap and projectConfig', () => {
1470      projectConfig.compileShared = true;
1471      const result = collectResevedFileNameInIDEConfig('', projectConfig, modulePathMap, []);
1472      expect(result).to.deep.equal(['path/to/module1', 'path/to/module2','module1','module2','path/to/build','etsFortgz','path/to/project','path/to/cache']);
1473    });
1474    it('should collect reserved file names from ohPackagePath and projectConfig', () => {
1475      projectConfig.byteCodeHar = true;
1476      const result = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, undefined, []);
1477      expect(result).to.deep.equal(['path/to/main', 'path/to/types','path/to/build','etsFortgz','path/to/project','path/to/cache']);
1478    });
1479    it('should collect reserved file names from moduleJsonPath and projectConfig', () => {
1480      projectConfig.aceModuleJsonPath = "./test/ut/initialization/testModuleJsonPath_0.json";
1481      const hasSrcEntry = collectResevedFileNameInIDEConfig('', projectConfig, undefined, []);
1482      expect(hasSrcEntry).to.deep.equal(['path/to/srcEntry','path/to/project','path/to/cache']);
1483
1484      projectConfig.aceModuleJsonPath = "./test/ut/initialization/testModuleJsonPath_1.json";
1485      const noSrcEntry = collectResevedFileNameInIDEConfig('', projectConfig, undefined, []);
1486      expect(noSrcEntry).to.deep.equal(['path/to/project','path/to/cache']);
1487    });
1488  });
1489
1490  describe('readNameCache', () => {
1491    let tempFilePath;
1492    let testData;
1493    let fsWriteFileSyncStub;
1494    let fsUnlinkSyncStub;
1495    let PropCollections;
1496    let renameFileNameModule;
1497
1498    beforeEach(() => {
1499      PropCollections = {
1500        historyMangledTable: {},
1501      };
1502      renameFileNameModule = {
1503        historyFileNameMangledTable: {},
1504      };
1505
1506      tempFilePath = './test/ut/initialization/tempNameCache.json';
1507      testData = {
1508        compileSdkVersion: '1.0.0',
1509        PropertyCache: { key1: 'value1', key2: 'value2' },
1510        FileNameCache: { key3: 'value3', key4: 'value4' },
1511        extraKey: '',
1512      };
1513
1514      fsWriteFileSyncStub = sinon.stub(fs, 'writeFileSync').callsFake((path, data) => {});
1515      fsUnlinkSyncStub = sinon.stub(fs, 'unlinkSync').callsFake((path) => {});
1516    });
1517
1518    afterEach(() => {
1519      fsWriteFileSyncStub.restore();
1520      fsUnlinkSyncStub.restore();
1521    });
1522
1523    it('should read and parse the name cache file correctly', () => {
1524      readNameCache(tempFilePath, printObfLogger);
1525
1526      expect(nameCacheMap.get('extraKey')).to.equal('');
1527    });
1528  });
1529
1530  describe('readNameCache', () => {
1531    let fsReadFileSyncStub;
1532    let logger;
1533    const testPath = './test/ut/initialization/tempNameCache.json';
1534
1535    beforeEach(() => {
1536      fsReadFileSyncStub = sinon.stub(fs, 'readFileSync').returns('{"compileSdkVersion":"1.0","PropertyCache":{},"FileNameCache":{}}');
1537      logger = { error: sinon.spy(), printError: (msg)=>{}};
1538    });
1539
1540    afterEach(() => {
1541      fsReadFileSyncStub.restore();
1542    });
1543
1544    it('should read the name cache file and parse its content', () => {
1545      readNameCache(testPath, printObfLogger);
1546      expect(PropCollections.historyMangledTable).to.deep.equal(new Map());
1547      expect(renameFileNameModule.historyFileNameMangledTable).to.deep.equal(new Map());
1548      expect(nameCacheMap.get('compileSdkVersion')).to.be.undefined;
1549      expect(logger.error.called).to.be.false;
1550    });
1551
1552    it('should handle errors when reading the file', () => {
1553      const mockLogger = {
1554        error: (message: string) => console.error(message),
1555      };
1556
1557      const nonExistentFilePath = './test/ut/initialization/nonExistentFile.json';
1558      try {
1559        readNameCache(nonExistentFilePath, printObfLogger);
1560      } catch (err) {
1561      }
1562      expect(logger.error.calledWith(`Failed to open ${nonExistentFilePath}. Error message: Test error`)).to.be.false;
1563    });
1564
1565    it('should handle errors when reading the file with hvigor errorCode', () => {
1566      const mockLogger = {
1567        error: (message: string) => console.error(message),
1568      };
1569
1570      const nonExistentFilePath = './test/ut/initialization/nonExistentFile.json';
1571      try {
1572        readNameCache(nonExistentFilePath, printObfHvigorLogger);
1573      } catch (err) {
1574      }
1575      const errorMessage = {
1576        code: '10804002',
1577        description: 'ArkTS compiler Error',
1578        cause: `Failed to open namecache file from ${nonExistentFilePath}, Error message: Test error`,
1579        position: nonExistentFilePath,
1580        solutions: [`Please check ${nonExistentFilePath} as error message suggested.`],
1581      };
1582      expect(logger.error.calledWith(errorMessage)).to.be.false;
1583    });
1584  });
1585
1586  describe('handleUniversalPathInObf', () => {
1587    it('should handle universal paths correctly', () => {
1588      const mergedObConfig: MergedConfig = {
1589        options: new ObOptionsForTest(),
1590        reservedPropertyNames: [],
1591        reservedGlobalNames: [],
1592        reservedNames: [],
1593        reservedFileNames: [],
1594        keepComments: [],
1595        keepSourceOfPaths: [],
1596        universalReservedPropertyNames: [],
1597        universalReservedGlobalNames: [],
1598        keepUniversalPaths: [/test\.js$/],
1599        excludeUniversalPaths: [/exclude\.js$/],
1600        excludePathSet: new Set(),
1601        mergeKeepOptions: () => {},
1602        mergeAllRules: () => {},
1603        sortAndDeduplicate: () => {},
1604        serializeMergedConfig: () => {
1605          return JSON.stringify(this);
1606        }
1607      };
1608      const allSourceFilePaths = new Set([
1609        'test.js',
1610        'exclude.js',
1611        'other.js',
1612      ]);
1613
1614      handleUniversalPathInObf(mergedObConfig, allSourceFilePaths);
1615      expect(mergedObConfig.keepSourceOfPaths).to.deep.equal(['test.js']);
1616      expect(mergedObConfig.excludePathSet).to.deep.equal(new Set(['exclude.js']));
1617    });
1618
1619    it('should return early if mergedObConfig is not provided or both keepUniversalPaths and excludeUniversalPaths are empty', () => {
1620      const mergedObConfig: MergedConfig = {
1621        options: new ObOptionsForTest(),
1622        reservedPropertyNames: [],
1623        reservedGlobalNames: [],
1624        reservedNames: [],
1625        reservedFileNames: [],
1626        keepComments: [],
1627        keepSourceOfPaths: [],
1628        universalReservedPropertyNames: [],
1629        universalReservedGlobalNames: [],
1630        keepUniversalPaths: [],
1631        excludeUniversalPaths: [],
1632        excludePathSet: new Set(),
1633        mergeKeepOptions: () => {},
1634        mergeAllRules: () => {},
1635        sortAndDeduplicate: () => {},
1636        serializeMergedConfig: () => {
1637          return JSON.stringify(this);
1638        }
1639      };
1640      const allSourceFilePaths = new Set([]);
1641      const result = handleUniversalPathInObf(mergedObConfig, allSourceFilePaths);
1642
1643      expect(result).to.be.undefined;
1644    });
1645  });
1646
1647  describe('getArkguardNameCache', () => {
1648    it('should return a JSON string with the correct structure', () => {
1649      const enablePropertyObfuscation = true;
1650      const enableFileNameObfuscation = true;
1651      const sdkVersion = '1.0.0';
1652      const entryPackageInfo = 'packageInfo';
1653
1654      const result = getArkguardNameCache(enablePropertyObfuscation, enableFileNameObfuscation, false, sdkVersion, entryPackageInfo);
1655
1656      try {
1657        JSON.parse(result);
1658        // If no error is thrown, the result is a valid JSON string
1659        console.log('Test passed: getArkguardNameCache returns a valid JSON string');
1660      } catch (error) {
1661        console.error('Test failed: getArkguardNameCache does not return a valid JSON string');
1662      }
1663    });
1664
1665    it('should include the correct compileSdkVersion and entryPackageInfo', () => {
1666      const enablePropertyObfuscation = false;
1667      const enableFileNameObfuscation = false;
1668      const sdkVersion = '2.0.0';
1669      const entryPackageInfo = 'anotherPackageInfo';
1670
1671      const result = getArkguardNameCache(enablePropertyObfuscation, enableFileNameObfuscation, false, sdkVersion, entryPackageInfo);
1672      const parsedResult = JSON.parse(result);
1673
1674      expect(parsedResult.compileSdkVersion).to.equal(sdkVersion);
1675      expect(parsedResult.entryPackageInfo).to.equal(entryPackageInfo);
1676    });
1677
1678    it('PropertyCache exists when enable export obfuscation', () => {
1679      const enablePropertyObfuscation = false;
1680      const enableFileNameObfuscation = false;
1681      const enableExportObfuscation = true;
1682      const sdkVersion = '2.0.0';
1683      const entryPackageInfo = 'anotherPackageInfo';
1684
1685      PropCollections.historyMangledTable.set("key1", "value1");
1686      PropCollections.historyMangledTable.set("key2", "value2");
1687      PropCollections.globalMangledTable.set("key3", "value3");
1688      PropCollections.globalMangledTable.set("key4", "value4");
1689      const result = getArkguardNameCache(enablePropertyObfuscation, enableFileNameObfuscation, enableExportObfuscation, sdkVersion, entryPackageInfo);
1690      const parsedResult = JSON.parse(result);
1691      PropCollections.historyMangledTable.clear();
1692      PropCollections.globalMangledTable.clear();
1693      expect('PropertyCache' in parsedResult).to.be.true;
1694      expect(parsedResult.PropertyCache.key1 === "value1").to.be.true;
1695      expect(parsedResult.PropertyCache.key2 === "value2").to.be.true;
1696      expect(parsedResult.PropertyCache.key3 === "value3").to.be.true;
1697      expect(parsedResult.PropertyCache.key4 === "value4").to.be.true;
1698    });
1699  });
1700
1701  describe('fillNameCache', function() {
1702    it('should correctly fill the name cache with the given table entries', function() {
1703      const table = new Map([
1704        ['key1', 'value1'],
1705        ['key2', 'value2'],
1706        ['key3', 'value3']
1707      ]);
1708      const nameCache = new Map();
1709
1710      fillNameCache(table, nameCache);
1711
1712      assert.deepEqual(nameCache, table);
1713    });
1714
1715    it('should handle empty tables gracefully', function() {
1716      const table = new Map();
1717      const nameCache = new Map();
1718
1719      fillNameCache(table, nameCache);
1720
1721      assert.deepEqual(nameCache, table);
1722    });
1723  });
1724
1725  describe('writeObfuscationNameCache', () => {
1726    let existsSyncSpy;
1727    let mkdirSyncSpy;
1728    let writeFileSyncSpy;
1729
1730    beforeEach(function() {
1731      existsSyncSpy = sinon.spy(fs, 'existsSync');
1732      mkdirSyncSpy = sinon.spy(fs, 'mkdirSync');
1733      writeFileSyncSpy = sinon.spy(fs, 'writeFileSync');
1734    });
1735
1736    afterEach(function() {
1737      existsSyncSpy.restore();
1738      mkdirSyncSpy.restore();
1739      writeFileSyncSpy.restore();
1740    });
1741
1742    it('should not write cache if projectConfig.arkObfuscator is false', () => {
1743      const projectConfig = {
1744        arkObfuscator: false,
1745        obfuscationMergedObConfig: {
1746          options: {
1747            enablePropertyObfuscation: true,
1748            enableFileNameObfuscation: true,
1749          },
1750        },
1751        etsLoaderVersion: '1.0.0',
1752      };
1753      const entryPackageInfo = 'testEntryPackageInfo';
1754      const obfuscationCacheDir = 'testCacheDir';
1755      const printNameCache = 'testPrintNameCache';
1756
1757      writeObfuscationNameCache(projectConfig, entryPackageInfo, obfuscationCacheDir, printNameCache);
1758
1759      expect(existsSyncSpy.called).to.be.false;
1760      expect(mkdirSyncSpy.called).to.be.false;
1761      expect(writeFileSyncSpy.called).to.be.false;
1762    });
1763    it('should write cache to obfuscationCacheDir if provided', () => {
1764      const projectConfig = {
1765        arkObfuscator: true,
1766        obfuscationMergedObConfig: {
1767          options: {
1768            enablePropertyObfuscation: true,
1769            enableFileNameObfuscation: true,
1770            enableExportObfusaction: true
1771          },
1772        },
1773        etsLoaderVersion: '1.0.0',
1774      };
1775      const entryPackageInfo = 'testEntryPackageInfo';
1776      const obfuscationCacheDir = './test/ut/initialization/testObfuscationCacheDir';
1777      const printNameCache = '';
1778      writeObfuscationNameCache(projectConfig, entryPackageInfo, obfuscationCacheDir, printNameCache);
1779      const defaultNameCachePath: string = path.join(obfuscationCacheDir, 'nameCache.json');
1780      const expectedContent = {
1781        "extraKey": "",
1782        "compileSdkVersion": "1.0.0",
1783        "entryPackageInfo": "testEntryPackageInfo",
1784        "PropertyCache": {},
1785        "FileNameCache": {}
1786      }
1787      const jsonData = fs.readFileSync(defaultNameCachePath,'utf-8');
1788      const result = JSON.parse(jsonData);
1789      expect(result).to.deep.equal(expectedContent);
1790      fs.unlinkSync(defaultNameCachePath);
1791      fs.rmdirSync(path.dirname(defaultNameCachePath));
1792    });
1793    it('should write cache to printNameCache if provided', () => {
1794      const projectConfig = {
1795        arkObfuscator: true,
1796        obfuscationMergedObConfig: {
1797          options: {
1798            enablePropertyObfuscation: true,
1799            enableFileNameObfuscation: true,
1800          },
1801        },
1802        etsLoaderVersion: '1.0.0',
1803      };
1804      const entryPackageInfo = 'testEntryPackageInfo';
1805      const obfuscationCacheDir = '';
1806      const printNameCache = './test/ut/initialization/printNameCache.json';
1807      writeObfuscationNameCache(projectConfig, entryPackageInfo, obfuscationCacheDir, printNameCache);
1808      const expectedContent = {
1809        "extraKey": "",
1810        "compileSdkVersion": "1.0.0",
1811        "entryPackageInfo": "testEntryPackageInfo",
1812        "PropertyCache": {},
1813        "FileNameCache": {}
1814      }
1815      const jsonData = fs.readFileSync(printNameCache,'utf-8');
1816      const result = JSON.parse(jsonData);
1817      expect(result).to.deep.equal(expectedContent);
1818      expect(existsSyncSpy.called).to.be.false;
1819      expect(mkdirSyncSpy.called).to.be.false;
1820      fs.unlinkSync(printNameCache);
1821    });
1822  });
1823
1824  describe('enableObfuscatedFilePathConfig', () => {
1825    it('should return false if in debug mode or no obfuscation config', () => {
1826      const projectConfig = {
1827        obfuscationMergedObConfig: null,
1828        buildMode: 'debug'
1829      };
1830      const result = enableObfuscatedFilePathConfig(true, projectConfig);
1831      expect(result).to.be.false;
1832    });
1833
1834    it('should return false if obfuscation is disabled or file name obfuscation is not enabled', () => {
1835      const projectConfig = {
1836        obfuscationMergedObConfig: {
1837          options: {
1838            disableObfuscation: true,
1839            enableFileNameObfuscation: false,
1840          },
1841        },
1842        buildMode: 'debug'
1843      };
1844      const result = enableObfuscatedFilePathConfig(false, projectConfig);
1845      expect(result).to.be.false;
1846    });
1847
1848    it('should return true if all conditions are met', () => {
1849      const projectConfig = {
1850        obfuscationMergedObConfig: {
1851          options: {
1852            disableObfuscation: false,
1853            enableFileNameObfuscation: true,
1854          },
1855        },
1856        buildMode: 'not debug'
1857      };
1858      const result = enableObfuscatedFilePathConfig(false, projectConfig);
1859      expect(result).to.be.true;
1860    });
1861  });
1862
1863  describe('handleObfuscatedFilePath', () => {
1864    it('should return the original file path if obfuscation is not enabled', () => {
1865      const filePath = '/path/to/file.js';
1866      const isPackageModules = false;
1867      const projectConfig = {
1868        enableFileNameObfuscation: false,
1869        buildMode: 'debug'
1870      };
1871
1872      const result = handleObfuscatedFilePath(filePath, isPackageModules, projectConfig);
1873
1874      expect(result).to.equal(filePath);
1875    });
1876
1877    it('should return the original file path if obfuscation is not enabled', () => {
1878      const filePath = '/path/to/file.txt';
1879      const isPackageModules = false;
1880      const projectConfig = {
1881        obfuscationMergedObConfig: null,
1882        buildMode: 'debug'
1883      };
1884      const result = handleObfuscatedFilePath(filePath, isPackageModules, projectConfig);
1885      expect(result).to.equal(filePath);
1886    });
1887
1888    it('should return the original file path if obfuscation is not enabled', () => {
1889      const filePath = '/path/to/file.txt';
1890      const isPackageModules = false;
1891      const projectConfig = {
1892        obfuscationMergedObConfig: null,
1893        buildMode: 'not debug'
1894      };
1895      const result = handleObfuscatedFilePath(filePath, isPackageModules, projectConfig);
1896      expect(result).to.equal(filePath);
1897    });
1898
1899    it('should return the unix formatted file path if obfuscation is enabled and is a package module', () => {
1900      const filePath = '/path/to/file.js';
1901      const isPackageModules = true;
1902      const projectConfig = {
1903        obfuscationMergedObConfig: {
1904          options: {
1905            disableObfuscation: false,
1906            enableFileNameObfuscation: true,
1907          },
1908        },
1909        buildMode: "not Debug"
1910      };
1911
1912      const result = handleObfuscatedFilePath(filePath, isPackageModules, projectConfig);
1913
1914      expect(result).to.equal(FileUtils.toUnixPath(filePath));
1915    });
1916
1917    it('should return the unix formatted file path if obfuscation is enabled and is a package module', () => {
1918      const filePath = '/path/to/file.js';
1919      const isPackageModules = true;
1920      const projectConfig = {
1921        obfuscationMergedObConfig: {
1922          options: {
1923            disableObfuscation: false,
1924            enableFileNameObfuscation: true,
1925          },
1926        },
1927        buildMode: ""
1928      };
1929
1930      const result = handleObfuscatedFilePath(filePath, isPackageModules, projectConfig);
1931
1932      expect(result).to.equal(FileUtils.toUnixPath(filePath));
1933    });
1934  });
1935
1936  describe('enableObfuscateFileName', () => {
1937    it('should return false if obfuscation is not enabled', () => {
1938      const isPackageModules = false;
1939      const projectConfig = {
1940        obfuscationMergedObConfig: null,
1941        buildMode: "not Debug"
1942      };
1943      const result = enableObfuscateFileName(isPackageModules, projectConfig);
1944      expect(result).to.be.false;
1945    });
1946
1947    it('should return true if obfuscation is enabled and not a package module', () => {
1948      const isPackageModules = false;
1949      const projectConfig = {
1950        obfuscationMergedObConfig: {
1951          options: {
1952            disableObfuscation: false,
1953            enableFileNameObfuscation: true,
1954          },
1955        },
1956        buildMode: "not Debug"
1957      };
1958      const result = enableObfuscateFileName(isPackageModules, projectConfig);
1959
1960      expect(result).to.be.true;
1961    });
1962
1963    it('should return false if obfuscation is enabled and is a package module', () => {
1964      const isPackageModules = true;
1965      const projectConfig = {
1966        obfuscationMergedObConfig: {
1967          options: {
1968            disableObfuscation: false,
1969            enableFileNameObfuscation: true,
1970          },
1971        },
1972        buildMode: "Debug"
1973      };
1974      const result = enableObfuscateFileName(isPackageModules, projectConfig);
1975      expect(result).to.be.false;
1976    });
1977
1978    it('should return false if obfuscation is enabled and is a package module', () => {
1979      const isPackageModules = true;
1980      const projectConfig = {
1981        obfuscationMergedObConfig: {
1982          options: {
1983            disableObfuscation: false,
1984            enableFileNameObfuscation: false,
1985          },
1986        },
1987        buildMode: "Debug"
1988      };
1989      const result = enableObfuscateFileName(isPackageModules, projectConfig);
1990      expect(result).to.be.false;
1991    });
1992
1993    it('should return false if obfuscation is enabled and is a package module', () => {
1994      const isPackageModules = true;
1995      const projectConfig = {
1996        obfuscationMergedObConfig: {},
1997        buildMode: "Debug"
1998      };
1999      const result = enableObfuscateFileName(isPackageModules, projectConfig);
2000      expect(result).to.be.false;
2001    });
2002
2003    it('should return false if obfuscation is enabled and is a package module', () => {
2004      const isPackageModules = true;
2005      const projectConfig = {
2006        obfuscationMergedObConfig: null,
2007        buildMode: "Debug"
2008      };
2009      const result = enableObfuscateFileName(isPackageModules, projectConfig);
2010      expect(result).to.be.false;
2011    });
2012
2013    it('should return false if obfuscation is enabled and is a package module', () => {
2014      const isPackageModules = true;
2015      const projectConfig = {
2016        obfuscationMergedObConfig: undefined,
2017        buildMode: "Debug"
2018      };
2019      const result = enableObfuscateFileName(isPackageModules, projectConfig);
2020      expect(result).to.be.false;
2021    });
2022
2023    it('should return false if obfuscation is enabled and is a package module', () => {
2024      const isPackageModules = true;
2025      const projectConfig = {
2026        obfuscationMergedObConfig: {
2027          options: {
2028            disableObfuscation: false,
2029            enableFileNameObfuscation: true,
2030          },
2031        },
2032        buildMode: "not Debug"
2033      };
2034      const result = enableObfuscateFileName(isPackageModules, projectConfig);
2035      expect(result).to.be.false;
2036    });
2037
2038    it('should return false if obfuscation is enabled and is a package module', () => {
2039      const isPackageModules = true;
2040      const projectConfig = {
2041        obfuscationMergedObConfig: {
2042          options: {
2043            disableObfuscation: false,
2044            enableFileNameObfuscation: false,
2045          },
2046        },
2047        buildMode: "not Debug"
2048      };
2049      const result = enableObfuscateFileName(isPackageModules, projectConfig);
2050      expect(result).to.be.false;
2051    });
2052
2053    it('should return false if obfuscation is enabled and is a package module', () => {
2054      const isPackageModules = true;
2055      const projectConfig = {
2056        obfuscationMergedObConfig: {
2057          options: {
2058            disableObfuscation: false,
2059            enableFileNameObfuscation: false,
2060          },
2061        },
2062        buildMode: "not Debug"
2063      };
2064      const result = enableObfuscateFileName(isPackageModules, projectConfig);
2065      expect(result).to.be.false;
2066    });
2067
2068    it('should return false if obfuscation is enabled and is a package module', () => {
2069      const isPackageModules = true;
2070      const projectConfig = {
2071        obfuscationMergedObConfig: {
2072          options: {
2073            disableObfuscation: false,
2074            enableFileNameObfuscation: true,
2075          },
2076        },
2077        buildMode: "not Debug"
2078      };
2079      const result = enableObfuscateFileName(isPackageModules, projectConfig);
2080      expect(result).to.be.false;
2081    });
2082
2083    it('should return false if obfuscation is enabled and bytecodeObf is enable', () => {
2084      const isPackageModules = false;
2085      const projectConfig = {
2086        obfuscationMergedObConfig: {
2087          options: {
2088            disableObfuscation: false,
2089            enableFileNameObfuscation: true,
2090            bytecodeObf: {
2091              enable: true
2092            },
2093          },
2094        },
2095        buildMode: "not Debug"
2096      };
2097      const result = enableObfuscatedFilePathConfig(isPackageModules, projectConfig);
2098      expect(result).to.be.false;
2099    });
2100  });
2101
2102  describe('getRelativeSourcePath', () => {
2103    it('should return the relative path of a file within the project root', () => {
2104      const filePath = '/Users/user/project/src/components/Button.js';
2105      const projectRootPath = '/Users/user/project';
2106      const expectedRelativePath = 'src/components/Button.js';
2107
2108      const result = getRelativeSourcePath(filePath, projectRootPath, '');
2109      expect(result).to.equal(expectedRelativePath);
2110    });
2111
2112    it('should return the relative path of a file within a specified project path', () => {
2113      const filePath = '/Users/user/project/src/components/Button.js';
2114      const belongProjectPath = '/Users/user/project/src';
2115      const expectedRelativePath = 'components/Button.js';
2116
2117      const result = getRelativeSourcePath(filePath, '', belongProjectPath);
2118      expect(result).to.equal(expectedRelativePath);
2119    });
2120
2121    it('should return the original path if no project root or belong project path is provided', () => {
2122      const filePath = '/Users/user/project/src/components/Button.js';
2123      const expectedRelativePath = filePath;
2124
2125      const result = getRelativeSourcePath(filePath, '', '');
2126      expect(result).to.equal(expectedRelativePath);
2127    });
2128  });
2129
2130  describe('printUnobfuscationReasons', () => {
2131    it('historyAllUnobfuscatedNamesMap is empty', () => {
2132      unobfuscationNamesObj['Index.ets'] = { 'abc': ['sdk'] };
2133      unobfuscationNamesObj['Test.ets'] = { 'abc_test': ['conf'] };
2134      printUnobfuscationReasons('', './keptNames.json');
2135      let keptNamesObj = {
2136        keptReasons: {},
2137        keptNames: {}
2138      };
2139      let keptNameString = fs.readFileSync('./keptNames.json', 'utf-8');
2140      const parsedObj = JSON.parse(keptNameString);
2141      keptNamesObj.keptReasons = parsedObj.keptReasons;
2142      keptNamesObj.keptNames = parsedObj.keptNames;
2143      expect(keptNamesObj.keptNames['Index.ets']['abc'][0]).to.equal('sdk');
2144      expect(keptNamesObj.keptNames['Test.ets']['abc_test'][0]).to.equal('conf');
2145      clearHistoryUnobfuscatedMap();
2146      clearUnobfuscationNamesObj();
2147    });
2148
2149    it('historyAllUnobfuscatedNamesMap is not empty', () => {
2150      historyAllUnobfuscatedNamesMap.set('Index.ets', { 'abc': ['sdk'] });
2151      historyAllUnobfuscatedNamesMap.set('Test.ets', { 'abc_test': ['conf'] });
2152      unobfuscationNamesObj['Index.ets'] = { 'abc': ['conf'] };
2153      unobfuscationNamesObj['Test2.ets'] = { 'abc_test2': ['lang'] };
2154      printUnobfuscationReasons('', './keptNames.json');
2155      let keptNamesObj = {
2156        keptReasons: {},
2157        keptNames: {}
2158      };
2159      let keptNameString = fs.readFileSync('./keptNames.json', 'utf-8');
2160      const parsedObj = JSON.parse(keptNameString);
2161      keptNamesObj.keptReasons = parsedObj.keptReasons;
2162      keptNamesObj.keptNames = parsedObj.keptNames;
2163      expect(keptNamesObj.keptNames['Index.ets']['abc'][0]).to.equal('conf');
2164      expect(keptNamesObj.keptNames['Test.ets']['abc_test'][0]).to.equal('conf');
2165      expect(keptNamesObj.keptNames['Test2.ets']['abc_test2'][0]).to.equal('lang');
2166      clearHistoryUnobfuscatedMap();
2167      clearUnobfuscationNamesObj();
2168    });
2169  });
2170
2171  describe('clearNameCache', () => {
2172    it('should clear historyMangledTable and nameCacheMap', () => {
2173      PropCollections.historyMangledTable.set('name1','name2');
2174      nameCacheMap.set('name1','name2');
2175      historyAllUnobfuscatedNamesMap.set('key', {'prop1': 'aaa'});
2176      historyUnobfuscatedPropMap.set('key', ['value']);
2177      clearNameCache();
2178      expect(PropCollections.historyMangledTable.size).to.be.equal(0);
2179      expect(nameCacheMap.size).to.be.equal(0);
2180      expect(historyAllUnobfuscatedNamesMap.size).to.equal(0);
2181      expect(historyUnobfuscatedPropMap.size).to.equal(0);
2182    });
2183  });
2184
2185  describe('emitConsumerConfigFiles', () => {
2186    it('should also collect atKeepNames when atKeep is enabled', () => {
2187      const atKeepExportedPath = path.join(__dirname, '../../testData/output/atKeep_obfuscation01.txt');
2188      const sourceObConfig = {
2189        selfConfig: {
2190          ruleOptions: {
2191            enable: true,
2192            rules: ['./test/testData/obfuscation/testAtKeep/obfuscation-rules-atKeep.txt']
2193          },
2194          consumerRules: ['./test/testData/obfuscation/testAtKeep/consumer-rules.txt'],
2195        },
2196        dependencies: { libraries: [], hars: [] },
2197        obfuscationCacheDir: './test/testData/cache',
2198        options: {
2199          disableObfuscation: false
2200        },
2201        exportRulePath: atKeepExportedPath,
2202        sdkApis: []
2203      };
2204      const projectConfig = {
2205        obfuscationOptions: sourceObConfig,
2206        compileHar: false,
2207        compileShared: true
2208      }
2209      const obConfigResolver = new ObConfigResolver(projectConfig, printObfLogger);
2210      obConfigResolver.resolveObfuscationConfigs();
2211      AtKeepCollections.clear();
2212      AtKeepCollections.keepAsConsumer.globalNames.add('globalName1');
2213      AtKeepCollections.keepAsConsumer.propertyNames.add('propertyName1');
2214      AtKeepCollections.keepSymbol.globalNames.add('globalName2');
2215      AtKeepCollections.keepSymbol.propertyNames.add('propertyName2');
2216      obConfigResolver.emitConsumerConfigFiles();
2217      const atKeepContent = fs.readFileSync(sourceObConfig.exportRulePath, 'utf-8');
2218      expect(atKeepContent).to.include('-enable-property-obfuscation');
2219      expect(atKeepContent).to.include('-keep-global-name');
2220      expect(atKeepContent).to.include('globalName00');
2221      expect(atKeepContent).to.include('globalName1');
2222      expect(atKeepContent).to.include('-keep-property-name');
2223      expect(atKeepContent).to.include('propertyName00');
2224      expect(atKeepContent).to.include('propertyName1');
2225      expect(atKeepContent).not.to.include('globalName2');
2226      expect(atKeepContent).not.to.include('propertyName2');
2227      FileUtils.deleteFile(atKeepExportedPath);
2228    });
2229
2230    it('should not collect atKeepNames when atKeep is not enabled', () => {
2231      const atKeepExportedPath = path.join(__dirname, '../../testData/output/atKeep_obfuscation02.txt');
2232      const sourceObConfig = {
2233        selfConfig: {
2234          ruleOptions: {
2235            enable: true,
2236            rules: ['./test/testData/obfuscation/testAtKeep/obfuscation-rules.txt']
2237          },
2238          consumerRules: ['./test/testData/obfuscation/testAtKeep/consumer-rules.txt'],
2239        },
2240        dependencies: { libraries: [], hars: [] },
2241        obfuscationCacheDir: './test/testData/cache',
2242        options: {
2243          disableObfuscation: false
2244        },
2245        exportRulePath: atKeepExportedPath,
2246        sdkApis: []
2247      };
2248      const projectConfig = {
2249        obfuscationOptions: sourceObConfig,
2250        compileHar: false,
2251        compileShared: true
2252      }
2253      AtKeepCollections.clear();
2254      const obConfigResolver = new ObConfigResolver(projectConfig, printObfLogger);
2255      obConfigResolver.resolveObfuscationConfigs();
2256      obConfigResolver.emitConsumerConfigFiles();
2257      const atKeepContent = fs.readFileSync(sourceObConfig.exportRulePath, 'utf-8');
2258      expect(atKeepContent).to.include('-enable-property-obfuscation');
2259      expect(atKeepContent).to.include('-keep-global-name');
2260      expect(atKeepContent).to.include('globalName00');
2261      expect(atKeepContent).not.to.include('globalName1');
2262      expect(atKeepContent).to.include('-keep-property-name');
2263      expect(atKeepContent).to.include('propertyName00');
2264      expect(atKeepContent).not.to.include('propertyName1');
2265      expect(atKeepContent).not.to.include('globalName2');
2266      expect(atKeepContent).not.to.include('propertyName2');
2267      FileUtils.deleteFile(atKeepExportedPath);
2268    });
2269  });
2270});
2271