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 rollupObject 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
16
17import { expect } from 'chai';
18import fs from "fs";
19import * as ts from 'typescript';
20import mocha from 'mocha';
21import path from "path";
22
23import {
24  MergedConfig,
25  ObConfigResolver,
26  collectResevedFileNameInIDEConfig,
27  getRelativeSourcePath,
28  handleKeepFilesAndGetDependencies,
29  sourceFileDependencies
30} from '../../../lib/fast_build/ark_compiler/common/ob_config_resolver';
31import {
32  OBFUSCATION_RULE_PATH,
33  OBFUSCATION_RULE_TEMPLATE_PATH
34} from '../mock/rollup_mock/path_config';
35import { OBFUSCATION_TOOL } from '../../../lib/fast_build/ark_compiler/common/ark_define';
36import { RELEASE } from '../../../lib/fast_build/ark_compiler/common/ark_define';
37import RollUpPluginMock from '../mock/rollup_mock/rollup_plugin_mock';
38import { ArkObfuscator } from 'arkguard';
39
40const OBFUSCATE_TESTDATA_DIR = path.resolve(__dirname, '../../../test/ark_compiler_ut/testdata/obfuscation');
41
42mocha.describe('test obfuscate config resolver api', function () {
43  mocha.before(function () {
44    this.rollup = new RollUpPluginMock();
45    let obfuscationContent = undefined;
46    try {
47      obfuscationContent = fs.readFileSync(OBFUSCATION_RULE_TEMPLATE_PATH, 'utf-8');
48      obfuscationContent = obfuscationContent.replace('OBFUSCATE_TESTDATA_DIR', OBFUSCATE_TESTDATA_DIR);
49      fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, obfuscationContent);
50    } catch (err) {
51      throw err;
52    }
53  });
54
55  mocha.afterEach(() => {
56    if (fs.existsSync(`${OBFUSCATION_RULE_PATH}`)) {
57      fs.unlinkSync(`${OBFUSCATION_RULE_PATH}`);
58    }
59  });
60
61  mocha.after(() => {
62    delete this.rollup;
63  });
64
65  mocha.it('1-1: test resolveDts', function () {
66    this.rollup.build(RELEASE);
67    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
68    this.rollup.share.projectConfig.obfuscationOptions = {
69      'selfConfig': {
70        'ruleOptions': {
71          'enable': true,
72          'rules': [ OBFUSCATION_RULE_PATH ]
73        },
74        'consumerRules': [],
75      },
76      'dependencies': {
77        'libraries': [],
78        'hars': []
79      }
80    };
81    const obConfig: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
82    const mergedObConfig: MergedConfig = obConfig.resolveObfuscationConfigs();
83    expect(mergedObConfig.options.enableToplevelObfuscation).to.be.true;
84    expect(mergedObConfig.options.enablePropertyObfuscation).to.be.false;
85
86    const reservedNames = mergedObConfig.reservedNames;
87    expect(reservedNames.length == 4).to.be.true;
88    expect(reservedNames.includes('matrix44')).to.be.true;
89    expect(reservedNames.includes('TranslateOption2')).to.be.true;
90    expect(reservedNames.includes('TestAdd')).to.be.true;
91    expect(reservedNames.includes('TestProperty')).to.be.true;
92
93    const reservedPropertyNames = mergedObConfig.reservedPropertyNames;
94    expect(reservedPropertyNames.length == 4).to.be.true;
95    expect(reservedPropertyNames.includes('matrix44')).to.be.true;
96    expect(reservedPropertyNames.includes('TranslateOption2')).to.be.true;
97    expect(reservedPropertyNames.includes('TestAdd')).to.be.true;
98    expect(reservedPropertyNames.includes('TestProperty')).to.be.true;
99
100    const reservedGlobalNames = mergedObConfig.reservedGlobalNames;
101    expect(reservedGlobalNames.length == 4).to.be.true;
102    expect(reservedGlobalNames.includes('matrix44')).to.be.true;
103    expect(reservedGlobalNames.includes('TranslateOption2')).to.be.true;
104    expect(reservedGlobalNames.includes('TestAdd')).to.be.true;
105    expect(reservedGlobalNames.includes('TestProperty')).to.be.true;
106
107    this.rollup.clearCache();
108  });
109
110  mocha.it('1-2: test resolveObfuscationConfigs: -enable-property-obfuscation', function () {
111    this.rollup.build(RELEASE);
112    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
113    const optionContent: string = '-enable-property-obfuscation';
114    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
115    this.rollup.share.projectConfig.obfuscationOptions = {
116      'selfConfig': {
117        'ruleOptions': {
118          'enable': true,
119          'rules': [OBFUSCATION_RULE_PATH]
120        },
121        'consumerRules': [],
122      },
123      'dependencies': {
124        'libraries': [],
125        'hars': []
126      }
127    };
128    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
129    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
130    const obOptions: ObOptions = mergedObConfig.options;
131    for (const [optionName, optionValue] of Object.entries(obOptions)) {
132      if (optionName === 'enablePropertyObfuscation') {
133        expect(optionValue).to.be.true;
134      } else {
135        if (typeof optionValue === 'boolean') {
136          expect(optionValue).to.be.false;
137        } else if (typeof optionValue === 'string') {
138          expect(optionValue === '').to.be.true;
139        }
140      }
141    }
142  });
143
144  mocha.it('1-3: test resolveObfuscationConfigs: -enable-property-obfuscation -enable-export-obfuscation', function () {
145    this.rollup.build(RELEASE);
146    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
147    const optionContent: string = '-enable-property-obfuscation\n-enable-export-obfuscation';
148    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
149    this.rollup.share.projectConfig.obfuscationOptions = {
150      'selfConfig': {
151        'ruleOptions': {
152          'enable': true,
153          'rules': [OBFUSCATION_RULE_PATH]
154        },
155        'consumerRules': [],
156      },
157      'dependencies': {
158        'libraries': [],
159        'hars': []
160      }
161    };
162    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
163    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
164    const obOptions: ObOptions = mergedObConfig.options;
165    for (const [optionName, optionValue] of Object.entries(obOptions)) {
166      if (optionName === 'enablePropertyObfuscation' || optionName === 'enableExportObfuscation') {
167        expect(optionValue).to.be.true;
168      } else {
169        if (typeof optionValue === 'boolean') {
170          expect(optionValue).to.be.false;
171        } else if (typeof optionValue === 'string') {
172          expect(optionValue === '').to.be.true;
173        }
174      }
175    }
176  });
177
178  mocha.it('1-3: test resolveObfuscationConfigs: -enable-property-obfuscation -enable-string-property-obfuscation', function () {
179    this.rollup.build(RELEASE);
180    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
181    const optionContent: string = '-enable-property-obfuscation\n-enable-string-property-obfuscation';
182    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
183    this.rollup.share.projectConfig.obfuscationOptions = {
184      'selfConfig': {
185        'ruleOptions': {
186          'enable': true,
187          'rules': [OBFUSCATION_RULE_PATH]
188        },
189        'consumerRules': [],
190      },
191      'dependencies': {
192        'libraries': [],
193        'hars': []
194      }
195    };
196    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
197    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
198    const obOptions: ObOptions = mergedObConfig.options;
199    for (const [optionName, optionValue] of Object.entries(obOptions)) {
200      if (optionName === 'enablePropertyObfuscation' || optionName === 'enableStringPropertyObfuscation') {
201        expect(optionValue).to.be.true;
202      } else {
203        if (typeof optionValue === 'boolean') {
204          expect(optionValue).to.be.false;
205        } else if (typeof optionValue === 'string') {
206          expect(optionValue === '').to.be.true;
207        }
208      }
209    }
210  });
211
212  mocha.it('1-4: test resolveObfuscationConfigs: -enable-property-obfuscation -enable-toplevel-obfuscation', function () {
213    this.rollup.build(RELEASE);
214    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
215    const optionContent: string = '-enable-property-obfuscation\n-enable-toplevel-obfuscation';
216    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
217    this.rollup.share.projectConfig.obfuscationOptions = {
218      'selfConfig': {
219        'ruleOptions': {
220          'enable': true,
221          'rules': [OBFUSCATION_RULE_PATH]
222        },
223        'consumerRules': [],
224      },
225      'dependencies': {
226        'libraries': [],
227        'hars': []
228      }
229    };
230    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
231    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
232    const obOptions: ObOptions = mergedObConfig.options;
233    for (const [optionName, optionValue] of Object.entries(obOptions)) {
234      if (optionName === 'enablePropertyObfuscation' || optionName === 'enableToplevelObfuscation') {
235        expect(optionValue).to.be.true;
236      } else {
237        if (typeof optionValue === 'boolean') {
238          expect(optionValue).to.be.false;
239        } else if (typeof optionValue === 'string') {
240          expect(optionValue === '').to.be.true;
241        }
242      }
243    }
244  });
245
246  mocha.it('1-5: test resolveObfuscationConfigs: enable all', function () {
247    this.rollup.build(RELEASE);
248    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
249    const optionContent: string = '-enable-property-obfuscation\n-enable-export-obfuscation\n-enable-filename-obfuscation\n'
250                                + '-enable-string-property-obfuscation\n-enable-toplevel-obfuscation';
251    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
252    this.rollup.share.projectConfig.obfuscationOptions = {
253      'selfConfig': {
254        'ruleOptions': {
255          'enable': true,
256          'rules': [OBFUSCATION_RULE_PATH]
257        },
258        'consumerRules': [],
259      },
260      'dependencies': {
261        'libraries': [],
262        'hars': []
263      }
264    };
265    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
266    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
267    const obOptions: ObOptions = mergedObConfig.options;
268    expect(obOptions.disableObfuscation).to.be.false;
269    expect(obOptions.enablePropertyObfuscation).to.be.true;
270    expect(obOptions.enableStringPropertyObfuscation).to.be.true;
271    expect(obOptions.enableToplevelObfuscation).to.be.true;
272    expect(obOptions.enableFileNameObfuscation).to.be.true;
273    expect(obOptions.enableExportObfuscation).to.be.true;
274    expect(obOptions.removeComments).to.be.false;
275    expect(obOptions.compact).to.be.false;
276    expect(obOptions.removeLog).to.be.false;
277  });
278
279  describe('2: test collectResevedFileNameInIDEConfig', function() {
280    let aceModuleJsonPath = '';
281    let ohPackagePath = '';
282    let projectConfig = {};
283    let modulePathMap = {};
284    let entryArray = [];
285    mocha.before('init config', function () {
286      aceModuleJsonPath = path.join(OBFUSCATE_TESTDATA_DIR, 'filename_obf/module.json');
287      ohPackagePath = path.join(OBFUSCATE_TESTDATA_DIR, 'filename_obf/oh-package.json5');
288      projectConfig = {
289        aceModuleJsonPath: aceModuleJsonPath,
290        projectPath: '/mnt/application/entry/src/main/ets',
291        cachePath: '/mnt/application/entry/build/default/cache/default/default@HarCompileArkTs/esmodules/release',
292        aceModuleBuild: '/mnt/application/entry/build/default/intermediates/loader_out',
293        compileShared: false,
294        compileHar: false,
295        byteCodeHar: false,
296      };
297      modulePathMap = {
298        'entry': '/mnt/application/entry',
299        'harpackagename': '/mnt/application/harPackageName'
300      };
301      entryArray = [
302        'entryability/EntryAbility',
303        'pages/Index'
304      ];
305    });
306
307    mocha.it('2-1: test collectResevedFileNameInIDEConfig in hsp module', function () {
308      projectConfig.compileShared = true;
309      projectConfig.compileHar = false;
310      projectConfig.byteCodeHar = false;
311      const acutualReservedFileNames: string[] = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, modulePathMap, entryArray);
312      const expectReservedFileNames = [
313        'entryability',
314        'EntryAbility',
315        'pages',
316        'Index',
317        '',
318        'mnt',
319        'application',
320        'entry',
321        '',
322        'mnt',
323        'application',
324        'harPackageName',
325        'entry',
326        'harpackagename',
327        '.',
328        'Index-oh-package.ets',
329        '.',
330        'Type-oh-package.ets',
331        '..',
332        '..',
333        'Index2.ets',
334        '',
335        'mnt',
336        'application',
337        'entry',
338        'build',
339        'default',
340        'intermediates',
341        'loader_out',
342        'etsFortgz',
343        '',
344        'mnt',
345        'application',
346        'entry',
347        'src',
348        'main',
349        'ets',
350        '',
351        'mnt',
352        'application',
353        'entry',
354        'build',
355        'default',
356        'cache',
357        'default',
358        'default@HarCompileArkTs',
359        'esmodules',
360        'release'
361      ];
362      expect(acutualReservedFileNames.toString() === expectReservedFileNames.toString()).to.be.true;
363    });
364  
365    mocha.it('2-2: test collectResevedFileNameInIDEConfig in hap module', function () {
366      projectConfig.compileShared = false;
367      projectConfig.compileHar = false;
368      projectConfig.byteCodeHar = false;
369      const acutualReservedFileNames: string[] = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, modulePathMap, entryArray);
370      const expectReservedFileNames = [
371        'entryability',
372        'EntryAbility',
373        'pages',
374        'Index',
375        '',
376        'mnt',
377        'application',
378        'entry',
379        '',
380        'mnt',
381        'application',
382        'harPackageName',
383        'entry',
384        'harpackagename',
385        '.',
386        'Index-oh-package.ets',
387        '.',
388        'Type-oh-package.ets',
389        '..',
390        '..',
391        'Index2.ets',
392        '',
393        'mnt',
394        'application',
395        'entry',
396        'src',
397        'main',
398        'ets',
399        '',
400        'mnt',
401        'application',
402        'entry',
403        'build',
404        'default',
405        'cache',
406        'default',
407        'default@HarCompileArkTs',
408        'esmodules',
409        'release'
410      ];
411      expect(acutualReservedFileNames.toString() === expectReservedFileNames.toString()).to.be.true;
412    });
413  
414    mocha.it('2-3: test collectResevedFileNameInIDEConfig in source har module', function () {
415      projectConfig.compileShared = false;
416      projectConfig.compileHar = true;
417      projectConfig.byteCodeHar = false;
418      const acutualReservedFileNames: string[] = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, modulePathMap, entryArray);
419      const expectReservedFileNames = [
420        'entryability',
421        'EntryAbility',
422        'pages',
423        'Index',
424        '',
425        'mnt',
426        'application',
427        'entry',
428        '',
429        'mnt',
430        'application',
431        'harPackageName',
432        'entry',
433        'harpackagename',
434        '.',
435        'Index-oh-package.ets',
436        '.',
437        'Type-oh-package.ets',
438        '..',
439        '..',
440        'Index2.ets',
441        '',
442        'mnt',
443        'application',
444        'entry',
445        'src',
446        'main',
447        'ets',
448        '',
449        'mnt',
450        'application',
451        'entry',
452        'build',
453        'default',
454        'cache',
455        'default',
456        'default@HarCompileArkTs',
457        'esmodules',
458        'release'
459      ];
460      expect(acutualReservedFileNames.toString() === expectReservedFileNames.toString()).to.be.true;
461    });
462  
463    mocha.it('2-4: test collectResevedFileNameInIDEConfig in byte code har module', function () {
464      projectConfig.compileShared = false;
465      projectConfig.compileHar = true;
466      projectConfig.byteCodeHar = true;
467      const acutualReservedFileNames: string[] = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, modulePathMap, entryArray);
468      const expectReservedFileNames = [
469        'entryability',
470        'EntryAbility',
471        'pages',
472        'Index',
473        '',
474        'mnt',
475        'application',
476        'entry',
477        '',
478        'mnt',
479        'application',
480        'harPackageName',
481        'entry',
482        'harpackagename',
483        '.',
484        'Index-oh-package.ets',
485        '.',
486        'Type-oh-package.ets',
487        '..',
488        '..',
489        'Index2.ets',
490        '',
491        'mnt',
492        'application',
493        'entry',
494        'build',
495        'default',
496        'intermediates',
497        'loader_out',
498        'etsFortgz',
499        '',
500        'mnt',
501        'application',
502        'entry',
503        'src',
504        'main',
505        'ets',
506        '',
507        'mnt',
508        'application',
509        'entry',
510        'build',
511        'default',
512        'cache',
513        'default',
514        'default@HarCompileArkTs',
515        'esmodules',
516        'release'
517      ];
518      expect(acutualReservedFileNames.toString() === expectReservedFileNames.toString()).to.be.true;
519    });
520  })
521
522  mocha.it('3-1: test resolveKeepConfig', function () {
523    this.rollup.build(RELEASE);
524    this.rollup.share.projectConfig.obfuscationOptions = {
525      'selfConfig': {
526        'ruleOptions': {
527          'enable': true,
528          'rules': [ OBFUSCATION_RULE_PATH ]
529        },
530        'consumerRules': [],
531      },
532      'dependencies': {
533        'libraries': [],
534        'hars': []
535      }
536    };
537    const keepConfigs = [
538      './bundle',
539      './testdata/**/filename_obf',
540      '!./testdata/obfuscation/filename_obf',
541      './testdata/obfuscation/filename_obf/..',
542      './testdata/obfuscation/keep?ts',
543      './testdata/obfuscation/*',
544      './^',
545      '$',
546      '!./testdata/expect/*',
547      './.ohpm/(*)'
548    ];
549    let configs = {
550      keepSourceOfPaths: [],
551      keepUniversalPaths: [],
552      excludeUniversalPaths: [],
553      excludePathSet: new Set<string>()
554    };
555    const currentFilePath = __filename;
556    const configPath = path.dirname(currentFilePath);
557    const obResolver = new ObConfigResolver(this.rollup.share.projectConfig, console, true);
558    obResolver.resolveKeepConfig(keepConfigs, configs, configPath);
559    let excludePathArray = Array.from(configs.excludePathSet);
560    expect(configs.keepSourceOfPaths[0].includes('bundle')).to.be.true;
561    expect(configs.keepSourceOfPaths[1].includes('obfuscation')).to.be.true;
562    expect(configs.keepUniversalPaths[0].toString().includes('filename_obf')).to.be.true;
563    expect(configs.keepUniversalPaths[1].toString().includes('keep[^/]ts')).to.be.true;
564    expect(configs.keepUniversalPaths[2].toString().includes('[^/]*')).to.be.true;
565    expect(configs.keepUniversalPaths[3].toString().includes('.ohpm')).to.be.true;
566    expect(configs.excludeUniversalPaths[0].toString().includes('[^/]*')).to.be.true;
567    expect(excludePathArray[0].includes('filename_obf')).to.be.true;
568  });
569
570  mocha.it('4-1: test getRelativeSourcePath: filePath starts with projectRootPath', function () {
571    const filePath = 'C:/projects/my-project/src/file.ts';
572    const projectRootPath = 'C:/projects/my-project';
573    const belongProjectPath = undefined;
574    const relativePath = getRelativeSourcePath(filePath, projectRootPath, belongProjectPath);
575    expect(relativePath).to.equal('src/file.ts');
576  });
577
578  mocha.it('4-2: test getRelativeSourcePath: filePath starts with belongProjectPath', function () {
579    const filePath = 'C:/projects/another-project/src/file.ts';
580    const projectRootPath = 'C:/projects/my-project';
581    const belongProjectPath = 'C:/projects/another-project';
582    const relativePath = getRelativeSourcePath(filePath, projectRootPath, belongProjectPath);
583    expect(relativePath).to.equal('src/file.ts');
584  });
585
586  mocha.it('4-3: test getRelativeSourcePath: undefined projectRootPath', function () {
587    const filePath = 'C:/projects/another-project/src/file.ts';
588    const projectRootPath = undefined;
589    const belongProjectPath = 'C:/projects/another-project';
590    const relativePath = getRelativeSourcePath(filePath, projectRootPath, belongProjectPath);
591    expect(relativePath).to.equal('src/file.ts');
592  });
593
594  mocha.it('4-4: test getRelativeSourcePath: undefined belongProjectPath ', function () {
595    const filePath = 'C:/projects/my-project/src/file.ts';
596    const projectRootPath = 'C:/projects/my-project';
597    const belongProjectPath = undefined;
598    const relativePath = getRelativeSourcePath(filePath, projectRootPath, belongProjectPath);
599    expect(relativePath).to.equal('src/file.ts');
600  });
601
602  mocha.it('5-1: test getFileNamesForScanningWhitelist: -keep is empty ', function () {
603    this.rollup.build(RELEASE);
604    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
605    const optionContent: string = '';
606    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
607    this.rollup.share.projectConfig.projectRootPath = ''
608    this.rollup.share.projectConfig.obfuscationOptions = {
609      'selfConfig': {
610        'ruleOptions': {
611          'enable': true,
612          'rules': [OBFUSCATION_RULE_PATH]
613        },
614        'consumerRules': [],
615      },
616      'dependencies': {
617        'libraries': [],
618        'hars': []
619      }
620    };
621    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
622    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
623    mergedObConfig.keepSourceOfPaths = [];
624    const keepFilesAndDependencies: Set<string> = handleKeepFilesAndGetDependencies(mergedObConfig,
625      this.rollup.share.projectConfig.projectRootPath, new ArkObfuscator());
626    expect(keepFilesAndDependencies.size === 0).to.be.true;
627  });
628
629  mocha.it('5-2: test getFileNamesForScanningWhitelist: unable export obfuscation ', function () {
630    this.rollup.build(RELEASE);
631    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
632    const optionContent: string = '-enble-export-obfuscation';
633    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
634    this.rollup.share.projectConfig.projectRootPath = ''
635    this.rollup.share.projectConfig.obfuscationOptions = {
636      'selfConfig': {
637        'ruleOptions': {
638          'enable': true,
639          'rules': [OBFUSCATION_RULE_PATH]
640        },
641        'consumerRules': [],
642      },
643      'dependencies': {
644        'libraries': [],
645        'hars': []
646      }
647    };
648    
649    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
650    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
651
652    let testFile1: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project1/file1.js');
653    let testFile2: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project1/file2.js');
654    let testFile3: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project2/file3.js');
655    let testFile4: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project2/file4.js');
656    let testFile5: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project3/file5.js');
657
658    mergedObConfig.keepSourceOfPaths = [
659      testFile1,
660      testFile3
661    ];
662    mergedObConfig.excludePathSet = new Set<string>([]);
663    mergedObConfig.options.enableExportObfuscation = true;
664    this.rollup.share.projectConfig.rootPathSet = new Set<string>([
665      path.resolve(__dirname, '../testdata/obfuscation_keeptest/project1/'),
666      path.resolve(__dirname, '../testdata/obfuscation_keeptest/project2/')
667    ]);
668    this.rollup.share.projectConfig.projectRootPath = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project1/');
669
670    const cache1: ts.ModeAwareCache<ts.ResolvedModuleFull | undefined> =
671      ts.createModeAwareCache<ts.ResolvedModuleFull | undefined>();
672    cache1.set('file1.ts', ts.ModuleKind.ESNext, { 
673      resolvedFileName: testFile2, 
674      isExternalLibraryImport: false, 
675      extension: ts.Extension.Js
676    });
677    cache1.set('file2.ts', ts.ModuleKind.ESNext, { 
678      resolvedFileName: testFile3, 
679      isExternalLibraryImport: false, 
680      extension: ts.Extension.Js
681    });
682    sourceFileDependencies.set(testFile1, cache1);
683
684    const cache2: ts.ModeAwareCache<ts.ResolvedModuleFull | undefined> =
685      ts.createModeAwareCache<ts.ResolvedModuleFull | undefined>();
686    cache2.set('file4.ts', ts.ModuleKind.ESNext, { 
687      resolvedFileName: testFile4, 
688      isExternalLibraryImport: false, 
689      extension: ts.Extension.Js
690    });
691    cache2.set('file5.ts', ts.ModuleKind.ESNext, { 
692      resolvedFileName: testFile5, 
693      isExternalLibraryImport: false, 
694      extension: ts.Extension.Js
695    });
696    sourceFileDependencies.set(testFile3, cache2);
697
698    let arkguardConfig: Object = {
699      mNameObfuscation: {
700        mEnable: true,
701        mNameGeneratorType: 1,
702        mRenameProperties: false,
703        mReservedProperties: [],
704        mTopLevel: false,
705        mReservedToplevelNames:[],
706      },
707      mKeepFileSourceCode: {
708        mKeepSourceOfPaths: [
709          testFile1,
710          testFile3
711        ],
712        mkeepFilesAndDependencies: []
713      },
714      mExportObfuscation: true,
715      mPerformancePrinter: []
716    };
717
718    let arkObfuscator: ArkObfuscator = new ArkObfuscator();
719    arkObfuscator.init(arkguardConfig);
720
721    const keepFilesAndDependencies: Set<string> = handleKeepFilesAndGetDependencies(mergedObConfig,
722      arkObfuscator, this.rollup.share.projectConfig);
723    expect(keepFilesAndDependencies.has(testFile1)).to.be.true;
724    expect(keepFilesAndDependencies.has(testFile2)).to.be.true;
725    expect(keepFilesAndDependencies.has(testFile3)).to.be.true;
726    expect(keepFilesAndDependencies.has(testFile4)).to.be.true;
727    expect(keepFilesAndDependencies.has(testFile5)).to.be.false;
728  });
729});