• 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 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";
22import sinon from 'sinon';
23
24import {
25  MergedConfig,
26  ObConfigResolver,
27  collectResevedFileNameInIDEConfig,
28  getNameCacheByPath,
29  getRelativeSourcePath,
30  handleKeepFilesAndGetDependencies,
31  setNewNameCache,
32  setUnobfuscationNames,
33  sourceFileDependencies,
34  writeObfuscatedFile,
35  IDENTIFIER_CACHE,
36  updateIncrementalCaches,
37  readProjectCaches,
38  getUpdatedFiles,
39  obfuscationPreprocess,
40  reObfuscate,
41  printObfLogger
42} from '../../../lib/fast_build/ark_compiler/common/ob_config_resolver';
43import {
44  OBFUSCATION_RULE_PATH,
45  OBFUSCATION_RULE_TEMPLATE_PATH
46} from '../mock/rollup_mock/path_config';
47import { OBFUSCATION_TOOL } from '../../../lib/fast_build/ark_compiler/common/ark_define';
48import { RELEASE } from '../../../lib/fast_build/ark_compiler/common/ark_define';
49import RollUpPluginMock from '../mock/rollup_mock/rollup_plugin_mock';
50import { ArkObfuscator, nameCacheMap, unobfuscationNamesObj, ProjectCollections } from 'arkguard';
51import * as arkUtils from '../../../lib/ark_utils'
52
53const OBFUSCATE_TESTDATA_DIR = path.resolve(__dirname, '../../../test/ark_compiler_ut/testdata/obfuscation');
54
55mocha.describe('test obfuscate config resolver api', function () {
56  mocha.before(function () {
57    this.rollup = new RollUpPluginMock();
58    let obfuscationContent = undefined;
59    try {
60      obfuscationContent = fs.readFileSync(OBFUSCATION_RULE_TEMPLATE_PATH, 'utf-8');
61      obfuscationContent = obfuscationContent.replace('OBFUSCATE_TESTDATA_DIR', OBFUSCATE_TESTDATA_DIR);
62      fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, obfuscationContent);
63    } catch (err) {
64      throw err;
65    }
66  });
67
68  mocha.afterEach(() => {
69    if (fs.existsSync(`${OBFUSCATION_RULE_PATH}`)) {
70      fs.unlinkSync(`${OBFUSCATION_RULE_PATH}`);
71    }
72  });
73
74  mocha.after(() => {
75    delete this.rollup;
76  });
77
78  mocha.it('1-1: test resolveDts', function () {
79    this.rollup.build(RELEASE);
80    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
81    this.rollup.share.projectConfig.obfuscationOptions = {
82      'selfConfig': {
83        'ruleOptions': {
84          'enable': true,
85          'rules': [ OBFUSCATION_RULE_PATH ]
86        },
87        'consumerRules': [],
88      },
89      'dependencies': {
90        'libraries': [],
91        'hars': []
92      }
93    };
94    const obConfig: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
95    const mergedObConfig: MergedConfig = obConfig.resolveObfuscationConfigs();
96    expect(mergedObConfig.options.enableToplevelObfuscation).to.be.true;
97    expect(mergedObConfig.options.enablePropertyObfuscation).to.be.false;
98
99    const reservedNames = mergedObConfig.reservedNames;
100    expect(reservedNames.length == 4).to.be.true;
101    expect(reservedNames.includes('matrix44')).to.be.true;
102    expect(reservedNames.includes('TranslateOption2')).to.be.true;
103    expect(reservedNames.includes('TestAdd')).to.be.true;
104    expect(reservedNames.includes('TestProperty')).to.be.true;
105
106    const reservedPropertyNames = mergedObConfig.reservedPropertyNames;
107    expect(reservedPropertyNames.length == 4).to.be.true;
108    expect(reservedPropertyNames.includes('matrix44')).to.be.true;
109    expect(reservedPropertyNames.includes('TranslateOption2')).to.be.true;
110    expect(reservedPropertyNames.includes('TestAdd')).to.be.true;
111    expect(reservedPropertyNames.includes('TestProperty')).to.be.true;
112
113    const reservedGlobalNames = mergedObConfig.reservedGlobalNames;
114    expect(reservedGlobalNames.length == 4).to.be.true;
115    expect(reservedGlobalNames.includes('matrix44')).to.be.true;
116    expect(reservedGlobalNames.includes('TranslateOption2')).to.be.true;
117    expect(reservedGlobalNames.includes('TestAdd')).to.be.true;
118    expect(reservedGlobalNames.includes('TestProperty')).to.be.true;
119
120    this.rollup.clearCache();
121  });
122
123  mocha.it('1-2: test resolveObfuscationConfigs: -enable-property-obfuscation', function () {
124    this.rollup.build(RELEASE);
125    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
126    const optionContent: string = '-enable-property-obfuscation';
127    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
128    this.rollup.share.projectConfig.obfuscationOptions = {
129      'selfConfig': {
130        'ruleOptions': {
131          'enable': true,
132          'rules': [OBFUSCATION_RULE_PATH]
133        },
134        'consumerRules': [],
135      },
136      'dependencies': {
137        'libraries': [],
138        'hars': []
139      }
140    };
141    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
142    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
143    const obOptions: ObOptions = mergedObConfig.options;
144    for (const [optionName, optionValue] of Object.entries(obOptions)) {
145      if (optionName === 'enablePropertyObfuscation') {
146        expect(optionValue).to.be.true;
147      } else {
148        if (typeof optionValue === 'boolean') {
149          expect(optionValue).to.be.false;
150        } else if (typeof optionValue === 'string') {
151          expect(optionValue === '').to.be.true;
152        }
153      }
154    }
155  });
156
157  mocha.it('1-3: test resolveObfuscationConfigs: -enable-property-obfuscation -enable-export-obfuscation', function () {
158    this.rollup.build(RELEASE);
159    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
160    const optionContent: string = '-enable-property-obfuscation\n-enable-export-obfuscation';
161    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
162    this.rollup.share.projectConfig.obfuscationOptions = {
163      'selfConfig': {
164        'ruleOptions': {
165          'enable': true,
166          'rules': [OBFUSCATION_RULE_PATH]
167        },
168        'consumerRules': [],
169      },
170      'dependencies': {
171        'libraries': [],
172        'hars': []
173      }
174    };
175    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
176    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
177    const obOptions: ObOptions = mergedObConfig.options;
178    for (const [optionName, optionValue] of Object.entries(obOptions)) {
179      if (optionName === 'enablePropertyObfuscation' || optionName === 'enableExportObfuscation') {
180        expect(optionValue).to.be.true;
181      } else {
182        if (typeof optionValue === 'boolean') {
183          expect(optionValue).to.be.false;
184        } else if (typeof optionValue === 'string') {
185          expect(optionValue === '').to.be.true;
186        }
187      }
188    }
189  });
190
191  mocha.it('1-3: test resolveObfuscationConfigs: -enable-property-obfuscation -enable-string-property-obfuscation', function () {
192    this.rollup.build(RELEASE);
193    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
194    const optionContent: string = '-enable-property-obfuscation\n-enable-string-property-obfuscation';
195    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
196    this.rollup.share.projectConfig.obfuscationOptions = {
197      'selfConfig': {
198        'ruleOptions': {
199          'enable': true,
200          'rules': [OBFUSCATION_RULE_PATH]
201        },
202        'consumerRules': [],
203      },
204      'dependencies': {
205        'libraries': [],
206        'hars': []
207      }
208    };
209    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
210    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
211    const obOptions: ObOptions = mergedObConfig.options;
212    for (const [optionName, optionValue] of Object.entries(obOptions)) {
213      if (optionName === 'enablePropertyObfuscation' || optionName === 'enableStringPropertyObfuscation') {
214        expect(optionValue).to.be.true;
215      } else {
216        if (typeof optionValue === 'boolean') {
217          expect(optionValue).to.be.false;
218        } else if (typeof optionValue === 'string') {
219          expect(optionValue === '').to.be.true;
220        }
221      }
222    }
223  });
224
225  mocha.it('1-4: test resolveObfuscationConfigs: -enable-property-obfuscation -enable-toplevel-obfuscation', function () {
226    this.rollup.build(RELEASE);
227    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
228    const optionContent: string = '-enable-property-obfuscation\n-enable-toplevel-obfuscation';
229    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
230    this.rollup.share.projectConfig.obfuscationOptions = {
231      'selfConfig': {
232        'ruleOptions': {
233          'enable': true,
234          'rules': [OBFUSCATION_RULE_PATH]
235        },
236        'consumerRules': [],
237      },
238      'dependencies': {
239        'libraries': [],
240        'hars': []
241      }
242    };
243    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
244    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
245    const obOptions: ObOptions = mergedObConfig.options;
246    for (const [optionName, optionValue] of Object.entries(obOptions)) {
247      if (optionName === 'enablePropertyObfuscation' || optionName === 'enableToplevelObfuscation') {
248        expect(optionValue).to.be.true;
249      } else {
250        if (typeof optionValue === 'boolean') {
251          expect(optionValue).to.be.false;
252        } else if (typeof optionValue === 'string') {
253          expect(optionValue === '').to.be.true;
254        }
255      }
256    }
257  });
258
259  mocha.it('1-5: test resolveObfuscationConfigs: enable all', function () {
260    this.rollup.build(RELEASE);
261    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
262    const optionContent: string = '-enable-property-obfuscation\n-enable-export-obfuscation\n-enable-filename-obfuscation\n'
263                                + '-enable-string-property-obfuscation\n-enable-toplevel-obfuscation';
264    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
265    this.rollup.share.projectConfig.obfuscationOptions = {
266      'selfConfig': {
267        'ruleOptions': {
268          'enable': true,
269          'rules': [OBFUSCATION_RULE_PATH]
270        },
271        'consumerRules': [],
272      },
273      'dependencies': {
274        'libraries': [],
275        'hars': []
276      }
277    };
278    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
279    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
280    const obOptions: ObOptions = mergedObConfig.options;
281    expect(obOptions.disableObfuscation).to.be.false;
282    expect(obOptions.enablePropertyObfuscation).to.be.true;
283    expect(obOptions.enableStringPropertyObfuscation).to.be.true;
284    expect(obOptions.enableToplevelObfuscation).to.be.true;
285    expect(obOptions.enableFileNameObfuscation).to.be.true;
286    expect(obOptions.enableExportObfuscation).to.be.true;
287    expect(obOptions.removeComments).to.be.false;
288    expect(obOptions.compact).to.be.false;
289    expect(obOptions.removeLog).to.be.false;
290  });
291
292  describe('2: test collectResevedFileNameInIDEConfig', function() {
293    let aceModuleJsonPath = '';
294    let ohPackagePath = '';
295    let projectConfig = {};
296    let modulePathMap = {};
297    let entryArray = [];
298    mocha.before('init config', function () {
299      aceModuleJsonPath = path.join(OBFUSCATE_TESTDATA_DIR, 'filename_obf/module.json');
300      ohPackagePath = path.join(OBFUSCATE_TESTDATA_DIR, 'filename_obf/oh-package.json5');
301      projectConfig = {
302        aceModuleJsonPath: aceModuleJsonPath,
303        projectPath: '/mnt/application/entry/src/main/ets',
304        cachePath: '/mnt/application/entry/build/default/cache/default/default@HarCompileArkTs/esmodules/release',
305        aceModuleBuild: '/mnt/application/entry/build/default/intermediates/loader_out',
306        compileShared: false,
307        compileHar: false,
308        byteCodeHar: false,
309      };
310      modulePathMap = {
311        'entry': '/mnt/application/entry',
312        'harpackagename': '/mnt/application/harPackageName'
313      };
314      entryArray = [
315        'entryability/EntryAbility',
316        'pages/Index'
317      ];
318    });
319
320    mocha.it('2-1: test collectResevedFileNameInIDEConfig in hsp module', function () {
321      projectConfig.compileShared = true;
322      projectConfig.compileHar = false;
323      projectConfig.byteCodeHar = false;
324      const acutualReservedFileNames: string[] = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, modulePathMap, entryArray);
325      const expectReservedFileNames = [
326        'entryability',
327        'EntryAbility',
328        'pages',
329        'Index',
330        '',
331        'mnt',
332        'application',
333        'entry',
334        '',
335        'mnt',
336        'application',
337        'harPackageName',
338        'entry',
339        'harpackagename',
340        '.',
341        'Index-oh-package.ets',
342        '.',
343        'Type-oh-package.ets',
344        '..',
345        '..',
346        'Index2.ets',
347        '',
348        'mnt',
349        'application',
350        'entry',
351        'build',
352        'default',
353        'intermediates',
354        'loader_out',
355        'etsFortgz',
356        '',
357        'mnt',
358        'application',
359        'entry',
360        'src',
361        'main',
362        'ets',
363        '',
364        'mnt',
365        'application',
366        'entry',
367        'build',
368        'default',
369        'cache',
370        'default',
371        'default@HarCompileArkTs',
372        'esmodules',
373        'release'
374      ];
375      expect(acutualReservedFileNames.toString() === expectReservedFileNames.toString()).to.be.true;
376    });
377
378    mocha.it('2-2: test collectResevedFileNameInIDEConfig in hap module', function () {
379      projectConfig.compileShared = false;
380      projectConfig.compileHar = false;
381      projectConfig.byteCodeHar = false;
382      const acutualReservedFileNames: string[] = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, modulePathMap, entryArray);
383      const expectReservedFileNames = [
384        'entryability',
385        'EntryAbility',
386        'pages',
387        'Index',
388        '',
389        'mnt',
390        'application',
391        'entry',
392        '',
393        'mnt',
394        'application',
395        'harPackageName',
396        'entry',
397        'harpackagename',
398        '.',
399        'Index-oh-package.ets',
400        '.',
401        'Type-oh-package.ets',
402        '..',
403        '..',
404        'Index2.ets',
405        '',
406        'mnt',
407        'application',
408        'entry',
409        'src',
410        'main',
411        'ets',
412        '',
413        'mnt',
414        'application',
415        'entry',
416        'build',
417        'default',
418        'cache',
419        'default',
420        'default@HarCompileArkTs',
421        'esmodules',
422        'release'
423      ];
424      expect(acutualReservedFileNames.toString() === expectReservedFileNames.toString()).to.be.true;
425    });
426
427    mocha.it('2-3: test collectResevedFileNameInIDEConfig in source har module', function () {
428      projectConfig.compileShared = false;
429      projectConfig.compileHar = true;
430      projectConfig.byteCodeHar = false;
431      const acutualReservedFileNames: string[] = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, modulePathMap, entryArray);
432      const expectReservedFileNames = [
433        'entryability',
434        'EntryAbility',
435        'pages',
436        'Index',
437        '',
438        'mnt',
439        'application',
440        'entry',
441        '',
442        'mnt',
443        'application',
444        'harPackageName',
445        'entry',
446        'harpackagename',
447        '.',
448        'Index-oh-package.ets',
449        '.',
450        'Type-oh-package.ets',
451        '..',
452        '..',
453        'Index2.ets',
454        '',
455        'mnt',
456        'application',
457        'entry',
458        'src',
459        'main',
460        'ets',
461        '',
462        'mnt',
463        'application',
464        'entry',
465        'build',
466        'default',
467        'cache',
468        'default',
469        'default@HarCompileArkTs',
470        'esmodules',
471        'release'
472      ];
473      expect(acutualReservedFileNames.toString() === expectReservedFileNames.toString()).to.be.true;
474    });
475
476    mocha.it('2-4: test collectResevedFileNameInIDEConfig in byte code har module', function () {
477      projectConfig.compileShared = false;
478      projectConfig.compileHar = true;
479      projectConfig.byteCodeHar = true;
480      const acutualReservedFileNames: string[] = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig, modulePathMap, entryArray);
481      const expectReservedFileNames = [
482        'entryability',
483        'EntryAbility',
484        'pages',
485        'Index',
486        '',
487        'mnt',
488        'application',
489        'entry',
490        '',
491        'mnt',
492        'application',
493        'harPackageName',
494        'entry',
495        'harpackagename',
496        '.',
497        'Index-oh-package.ets',
498        '.',
499        'Type-oh-package.ets',
500        '..',
501        '..',
502        'Index2.ets',
503        '',
504        'mnt',
505        'application',
506        'entry',
507        'build',
508        'default',
509        'intermediates',
510        'loader_out',
511        'etsFortgz',
512        '',
513        'mnt',
514        'application',
515        'entry',
516        'src',
517        'main',
518        'ets',
519        '',
520        'mnt',
521        'application',
522        'entry',
523        'build',
524        'default',
525        'cache',
526        'default',
527        'default@HarCompileArkTs',
528        'esmodules',
529        'release'
530      ];
531      expect(acutualReservedFileNames.toString() === expectReservedFileNames.toString()).to.be.true;
532    });
533  })
534
535  mocha.it('4-1: test getRelativeSourcePath: filePath starts with projectRootPath', function () {
536    const filePath = 'C:/projects/my-project/src/file.ts';
537    const projectRootPath = 'C:/projects/my-project';
538    const belongProjectPath = undefined;
539    const relativePath = getRelativeSourcePath(filePath, projectRootPath, belongProjectPath);
540    expect(relativePath).to.equal('src/file.ts');
541  });
542
543  mocha.it('4-2: test getRelativeSourcePath: filePath starts with belongProjectPath', function () {
544    const filePath = 'C:/projects/another-project/src/file.ts';
545    const projectRootPath = 'C:/projects/my-project';
546    const belongProjectPath = 'C:/projects/another-project';
547    const relativePath = getRelativeSourcePath(filePath, projectRootPath, belongProjectPath);
548    expect(relativePath).to.equal('src/file.ts');
549  });
550
551  mocha.it('4-3: test getRelativeSourcePath: undefined projectRootPath', function () {
552    const filePath = 'C:/projects/another-project/src/file.ts';
553    const projectRootPath = undefined;
554    const belongProjectPath = 'C:/projects/another-project';
555    const relativePath = getRelativeSourcePath(filePath, projectRootPath, belongProjectPath);
556    expect(relativePath).to.equal('src/file.ts');
557  });
558
559  mocha.it('4-4: test getRelativeSourcePath: undefined belongProjectPath ', function () {
560    const filePath = 'C:/projects/my-project/src/file.ts';
561    const projectRootPath = 'C:/projects/my-project';
562    const belongProjectPath = undefined;
563    const relativePath = getRelativeSourcePath(filePath, projectRootPath, belongProjectPath);
564    expect(relativePath).to.equal('src/file.ts');
565  });
566
567  mocha.it('5-1: test getFileNamesForScanningWhitelist: -keep is empty ', function () {
568    this.rollup.build(RELEASE);
569    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
570    const optionContent: string = '';
571    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
572    this.rollup.share.projectConfig.projectRootPath = ''
573    this.rollup.share.projectConfig.obfuscationOptions = {
574      'selfConfig': {
575        'ruleOptions': {
576          'enable': true,
577          'rules': [OBFUSCATION_RULE_PATH]
578        },
579        'consumerRules': [],
580      },
581      'dependencies': {
582        'libraries': [],
583        'hars': []
584      }
585    };
586    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
587    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
588    mergedObConfig.keepSourceOfPaths = [];
589    const keepFilesAndDependencies: Set<string> = handleKeepFilesAndGetDependencies(mergedObConfig,
590      this.rollup.share.projectConfig.projectRootPath, new ArkObfuscator());
591    expect(keepFilesAndDependencies.size === 0).to.be.true;
592  });
593
594  mocha.it('5-2: test getFileNamesForScanningWhitelist: unable export obfuscation ', function () {
595    this.rollup.build(RELEASE);
596    const logger: object = this.rollup.share.getLogger(OBFUSCATION_TOOL);
597    const optionContent: string = '-enble-export-obfuscation';
598    fs.writeFileSync(`${OBFUSCATION_RULE_PATH}`, optionContent);
599    this.rollup.share.projectConfig.projectRootPath = ''
600    this.rollup.share.projectConfig.obfuscationOptions = {
601      'selfConfig': {
602        'ruleOptions': {
603          'enable': true,
604          'rules': [OBFUSCATION_RULE_PATH]
605        },
606        'consumerRules': [],
607      },
608      'dependencies': {
609        'libraries': [],
610        'hars': []
611      }
612    };
613
614    const obConfigResolver: ObConfigResolver =  new ObConfigResolver(this.rollup.share.projectConfig, logger, true);
615    const mergedObConfig: MergedConfig = obConfigResolver.resolveObfuscationConfigs();
616
617    let testFile1: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project1/file1.js');
618    let testFile2: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project1/file2.js');
619    let testFile3: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project2/file3.js');
620    let testFile4: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project2/file4.js');
621    let testFile5: string = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project3/file5.js');
622
623    mergedObConfig.keepSourceOfPaths = [
624      testFile1,
625      testFile3
626    ];
627    mergedObConfig.excludePathSet = new Set<string>([]);
628    mergedObConfig.options.enableExportObfuscation = true;
629    this.rollup.share.projectConfig.rootPathSet = new Set<string>([
630      path.resolve(__dirname, '../testdata/obfuscation_keeptest/project1/'),
631      path.resolve(__dirname, '../testdata/obfuscation_keeptest/project2/')
632    ]);
633    this.rollup.share.projectConfig.projectRootPath = path.resolve(__dirname, '../testdata/obfuscation_keeptest/project1/');
634
635    const cache1: ts.ModeAwareCache<ts.ResolvedModuleFull | undefined> =
636      ts.createModeAwareCache<ts.ResolvedModuleFull | undefined>();
637    cache1.set('file1.ts', ts.ModuleKind.ESNext, {
638      resolvedFileName: testFile2,
639      isExternalLibraryImport: false,
640      extension: ts.Extension.Js
641    });
642    cache1.set('file2.ts', ts.ModuleKind.ESNext, {
643      resolvedFileName: testFile3,
644      isExternalLibraryImport: false,
645      extension: ts.Extension.Js
646    });
647    sourceFileDependencies.set(testFile1, cache1);
648
649    const cache2: ts.ModeAwareCache<ts.ResolvedModuleFull | undefined> =
650      ts.createModeAwareCache<ts.ResolvedModuleFull | undefined>();
651    cache2.set('file4.ts', ts.ModuleKind.ESNext, {
652      resolvedFileName: testFile4,
653      isExternalLibraryImport: false,
654      extension: ts.Extension.Js
655    });
656    cache2.set('file5.ts', ts.ModuleKind.ESNext, {
657      resolvedFileName: testFile5,
658      isExternalLibraryImport: false,
659      extension: ts.Extension.Js
660    });
661    sourceFileDependencies.set(testFile3, cache2);
662
663    let arkguardConfig: Object = {
664      mNameObfuscation: {
665        mEnable: true,
666        mNameGeneratorType: 1,
667        mRenameProperties: false,
668        mReservedProperties: [],
669        mTopLevel: false,
670        mReservedToplevelNames:[],
671      },
672      mKeepFileSourceCode: {
673        mKeepSourceOfPaths: [
674          testFile1,
675          testFile3
676        ],
677        mkeepFilesAndDependencies: []
678      },
679      mExportObfuscation: true,
680      mPerformancePrinter: []
681    };
682
683    let arkObfuscator: ArkObfuscator = new ArkObfuscator();
684    arkObfuscator.init(arkguardConfig);
685
686    const keepFilesAndDependencies: Set<string> = handleKeepFilesAndGetDependencies(mergedObConfig,
687      arkObfuscator, this.rollup.share.projectConfig);
688    expect(keepFilesAndDependencies.has(testFile1)).to.be.true;
689    expect(keepFilesAndDependencies.has(testFile2)).to.be.true;
690    expect(keepFilesAndDependencies.has(testFile3)).to.be.true;
691    expect(keepFilesAndDependencies.has(testFile4)).to.be.true;
692    expect(keepFilesAndDependencies.has(testFile5)).to.be.false;
693  });
694
695  mocha.it('6-1: test getHistoryNameCache: isDeclaration false', function () {
696    const moduleInfo = {
697      content: 'module content',
698      buildFilePath: 'build/path/to/file.ts',
699      relativeSourceFilePath: 'src/file.ts',
700      originSourceFilePath: 'C:/projects/my-project/src/file.ts'
701    };
702    nameCacheMap.set('src/file.ts', {
703      [IDENTIFIER_CACHE]: {
704        'identifier1:1': 'obfuscated1',
705        identifier2: 'obfuscated2'
706      }
707    });
708    const isDeclaration: boolean = false;
709    const projectRootPath: string = 'C:/projects/my-project';
710    const result: Map<string, string> = getNameCacheByPath(moduleInfo, isDeclaration, projectRootPath);
711    nameCacheMap.clear();
712    expect(result.size).to.equal(2);
713    expect(result.get('identifier1')).to.equal('obfuscated1');
714    expect(result.get('identifier2')).to.equal('obfuscated2');
715  });
716
717  mocha.it('6-2: test getHistoryNameCache: isDeclaration true', function () {
718    const moduleInfo = {
719      content: 'module content',
720      buildFilePath: 'build/path/to/file.d.ts',
721      relativeSourceFilePath: 'src/file.ts',
722      originSourceFilePath: 'C:/projects/my-project/src/file.ts'
723    };
724    nameCacheMap.set('src/file.ts', {
725      [IDENTIFIER_CACHE]: {
726        'identifier1:1': 'obfuscated1',
727        identifier2: 'obfuscated2'
728      }
729    });
730    const isDeclaration: boolean = true;
731    const projectRootPath: string = 'C:/projects/my-project';
732    const result: Map<string, string> = getNameCacheByPath(moduleInfo, isDeclaration, projectRootPath);
733    nameCacheMap.clear();
734    expect(result.size).to.equal(2);
735    expect(result.get('identifier1')).to.equal('obfuscated1');
736    expect(result.get('identifier2')).to.equal('obfuscated2');
737  });
738
739  mocha.it('7-1: test setNewNameCache: isOhModule is false', function () {
740    const moduleInfo = {
741      content: 'module content',
742      buildFilePath: 'build/path/to/file.ts',
743      relativeSourceFilePath: 'src/file.ts',
744      originSourceFilePath: 'C:/projects/my-project/src/file.ts'
745    };
746    nameCacheMap.set('src/file.ts', {
747      [IDENTIFIER_CACHE]: {
748        'identifier1:1': 'obfuscated1',
749        identifier2: 'obfuscated2'
750      }
751    });
752    const newNameCache = {
753      [IDENTIFIER_CACHE]: {
754        'identifier3:3': 'obfuscated3'
755      }
756    };
757    const isDeclaration: boolean = false;
758    const projectConfig: Object = {
759      obfuscationMergedObConfig: { options: { enableFileNameObfuscation: true } },
760      projectRootPath: '/projectRoot',
761      packageDir: 'oh_modules',
762      modulePathMap: {
763        module1: '/externalModule'
764      },
765    };
766    setNewNameCache(newNameCache, isDeclaration, moduleInfo, projectConfig);
767    const result: string | {} = nameCacheMap.get(moduleInfo.relativeSourceFilePath);
768    nameCacheMap.clear();
769
770    expect(result[IDENTIFIER_CACHE]['identifier3:3'] === 'obfuscated3').to.be.true;
771    expect(result.obfName === 'src/file.ts').to.be.false;
772  });
773
774  mocha.it('7-2: test setNewNameCache: isOhModule is true', function () {
775    const moduleInfo = {
776      content: 'module content',
777      buildFilePath: 'build/path/to/file.ts',
778      relativeSourceFilePath: 'src/file.ts',
779      originSourceFilePath: '/projectRoot/oh_modules/src/file.ts'
780    };
781    nameCacheMap.set('src/file.ts', {
782      [IDENTIFIER_CACHE]: {
783        'identifier1:1': 'obfuscated1',
784        identifier2: 'obfuscated2'
785      }
786    });
787    const newNameCache = {
788      [IDENTIFIER_CACHE]: {
789        'identifier3:3': 'obfuscated3'
790      }
791    };
792    const isDeclaration: boolean = false;
793    const projectConfig: Object = {
794      obfuscationMergedObConfig: { options: { enableFileNameObfuscation: true } },
795      projectRootPath: '/projectRoot',
796      packageDir: 'oh_modules'
797    };
798    setNewNameCache(newNameCache, isDeclaration, moduleInfo, projectConfig);
799    const result: string | {} = nameCacheMap.get(moduleInfo.relativeSourceFilePath);
800    nameCacheMap.clear();
801
802    expect(result[IDENTIFIER_CACHE]['identifier3:3'] === 'obfuscated3').to.be.true;
803    expect(result.obfName === 'src/file.ts').to.be.true;
804  });
805
806  mocha.it('8-1: test setUnobfuscationNames', function () {
807    const relativeSourceFilePath: string = 'src/file.ts';
808    const unobfuscationNameMap: Map<string, Set<string>> = new Map([
809      ['key1', new Set(['value1', 'value2'])],
810      ['key2', new Set(['value3'])]
811    ]);
812    const isDeclaration: boolean = false;
813
814    setUnobfuscationNames(unobfuscationNameMap, relativeSourceFilePath, isDeclaration);
815
816    expect(unobfuscationNamesObj[relativeSourceFilePath]).to.deep.equal({
817      key1: ['value1', 'value2'],
818      key2: ['value3']
819    });
820  });
821
822  mocha.it('9-1: test writeFile', function () {
823    const newFilePath: string = '../../test/ark_compiler_ut/testdata/writeFile.ts';
824    const content: string = 'obfuscated code';
825
826    writeObfuscatedFile(newFilePath, content);
827
828    expect(fs.existsSync(newFilePath)).to.be.true;
829    const fileContent: string = fs.readFileSync(newFilePath, 'utf-8');
830    expect(fileContent).to.equal(content);
831    fs.unlinkSync(newFilePath);
832  });
833
834  mocha.describe('10: test Obfuscation Functions', function () {
835    let arkObfuscatorStub;
836    let filePathManagerStub;
837    let fileContentManagerStub;
838    let projectWhiteListManagerStub;
839
840    mocha.beforeEach(function () {
841      filePathManagerStub = {
842        getDeletedSourceFilePaths: sinon.stub(),
843        createOrUpdateSourceFilePaths: sinon.stub(),
844        addedSourceFilePaths: new Set(),
845      };
846      fileContentManagerStub = {
847        deleteFileContent: sinon.stub(),
848        readFileNamesMap: sinon.stub(),
849        getSortedFiles: sinon.stub(),
850        fileNamesMap: new Map(),
851        readFileContent: sinon.stub(),
852      };
853      projectWhiteListManagerStub = {
854        createOrUpdateWhiteListCaches: sinon.stub(),
855        getShouldReObfuscate: sinon.stub(),
856      };
857      arkObfuscatorStub = {
858        filePathManager: filePathManagerStub,
859        fileContentManager: fileContentManagerStub,
860        shouldReObfuscate: false,
861        isIncremental: false,
862      };
863      ProjectCollections.initProjectWhiteListManager('', false, false);
864      sinon.stub(ProjectCollections, 'projectWhiteListManager').value(projectWhiteListManagerStub);
865    });
866
867    mocha.afterEach(function () {
868      sinon.restore();
869    });
870
871    mocha.describe('10-1: updateIncrementalCaches', function () {
872      mocha.it('10-1-1: should update caches and set shouldReObfuscate flag if needed', function () {
873        const deletedFilesSet = new Set(['file1.ts', 'file2.ts']);
874        filePathManagerStub.getDeletedSourceFilePaths.returns(deletedFilesSet);
875        projectWhiteListManagerStub.getShouldReObfuscate.returns(true);
876
877        updateIncrementalCaches(arkObfuscatorStub);
878
879        expect(projectWhiteListManagerStub.createOrUpdateWhiteListCaches.calledWith(deletedFilesSet)).to.be.true;
880        expect(fileContentManagerStub.deleteFileContent.calledWith(deletedFilesSet)).to.be.true;
881        expect(arkObfuscatorStub.shouldReObfuscate).to.be.true;
882      });
883
884      mocha.it('10-1-2: should not set shouldReObfuscate flag if not needed', function () {
885        const deletedFilesSet = new Set(['file1.ts', 'file2.ts']);
886        filePathManagerStub.getDeletedSourceFilePaths.returns(deletedFilesSet);
887        projectWhiteListManagerStub.getShouldReObfuscate.returns(false);
888
889        updateIncrementalCaches(arkObfuscatorStub);
890
891        expect(arkObfuscatorStub.shouldReObfuscate).to.be.false;
892      });
893    });
894
895    mocha.describe('10-2: readProjectCaches', function () {
896      mocha.it('10-2-1: should update source file paths and read file names map if incremental', function () {
897        const allFiles = new Set(['file1.ts', 'file2.ts']);
898        arkObfuscatorStub.isIncremental = true;
899
900        readProjectCaches(allFiles, arkObfuscatorStub);
901
902        expect(filePathManagerStub.createOrUpdateSourceFilePaths.calledWith(allFiles)).to.be.true;
903        expect(fileContentManagerStub.readFileNamesMap.calledOnce).to.be.true;
904      });
905
906      mocha.it('10-2-2: should not read file names map if not incremental', function () {
907        const allFiles = new Set(['file1.ts', 'file2.ts']);
908        arkObfuscatorStub.isIncremental = false;
909
910        readProjectCaches(allFiles, arkObfuscatorStub);
911
912        expect(fileContentManagerStub.readFileNamesMap.called).to.be.false;
913      });
914    });
915
916    mocha.describe('10-3: getUpdatedFiles', function () {
917      mocha.it('10-3-1: should return updated files if incremental', function () {
918        const sourceProjectConfig = {
919          arkObfuscator: {
920            isIncremental: true,
921            filePathManager: {
922              addedSourceFilePaths: new Set(['file3.ts']),
923            },
924          },
925        };
926        const allSourceFilePaths = new Set(['file1.ts', 'file2.ts', 'file3.d.ts', 'file4.d.ets']);
927        const moduleSourceFiles = [{ moduleId: 'file1.ts' }, { moduleId: 'file2.ts' }];
928        const updatedFiles = getUpdatedFiles(sourceProjectConfig, allSourceFilePaths, moduleSourceFiles);
929        expect(updatedFiles).to.deep.equal(new Set(['file1.ts', 'file2.ts', 'file3.ts', 'file3.d.ts', 'file4.d.ets']));
930      });
931
932      mocha.it('10-3-2: should return all source files if not incremental', function () {
933        const sourceProjectConfig = {
934          arkObfuscator: {
935            isIncremental: false,
936          },
937        };
938        const allSourceFilePaths = new Set(['file1.ts', 'file2.ts', 'file3.d.ts']);
939        const moduleSourceFiles = [{ moduleId: 'file1.ts' }, { moduleId: 'file2.ts' }];
940        const updatedFiles = getUpdatedFiles(sourceProjectConfig, allSourceFilePaths, moduleSourceFiles);
941        expect(updatedFiles).to.deep.equal(allSourceFilePaths);
942      });
943    });
944
945    mocha.describe('10-4: obfuscationPreprocess', function () {
946      mocha.it('10-4-1: should call readProjectCaches and updateIncrementalCaches if arkObfuscator exists', function () {
947        const sourceProjectConfig = {
948          arkObfuscator: arkObfuscatorStub,
949        };
950        const allSourceFilePaths = new Set(['file1.ts', 'file2.ts']);
951        const obfuscationConfig = {};
952        const keepFilesAndDependencies = new Set();
953        const moduleSourceFiles = [{ moduleId: 'file1.ts' }, { moduleId: 'file2.ts' }];
954
955        obfuscationPreprocess(
956          sourceProjectConfig,
957          obfuscationConfig,
958          allSourceFilePaths,
959          keepFilesAndDependencies,
960          moduleSourceFiles
961        );
962
963        expect(filePathManagerStub.createOrUpdateSourceFilePaths.calledWith(allSourceFilePaths)).to.be.true;
964        expect(projectWhiteListManagerStub.createOrUpdateWhiteListCaches.called).to.be.true;
965        expect(ProjectCollections.projectWhiteListManager).to.be.undefined;
966      });
967
968      mocha.it('10-4-2: should not call readProjectCaches if arkObfuscator does not exist', function () {
969        const sourceProjectConfig = {};
970        const allSourceFilePaths = new Set(['file1.ts', 'file2.ts']);
971        const obfuscationConfig = {};
972        const keepFilesAndDependencies = new Set();
973        const moduleSourceFiles = [{ moduleId: 'file1.ts' }, { moduleId: 'file2.ts' }];
974
975        obfuscationPreprocess(
976          sourceProjectConfig,
977          obfuscationConfig,
978          allSourceFilePaths,
979          keepFilesAndDependencies,
980          moduleSourceFiles
981        );
982
983        expect(filePathManagerStub.createOrUpdateSourceFilePaths.called).to.be.false;
984      });
985    });
986
987    mocha.describe('10-5: reObfuscate', function () {
988      mocha.it('10-5-1: should update harFilesRecord if is declaration file', async function () {
989        const harFilesRecord = new Map();
990        const logger = {};
991        const projectConfig = {};
992        const sortedFiles = ['file1.d.ts', 'file2.d.ts'];
993        const fileContentObj1 = {
994          moduleInfo: {
995            originSourceFilePath: 'file1.d.ts',
996            buildFilePath: 'file1.d.ts',
997            content: 'content1',
998          },
999          previousStageSourceMap: {},
1000        };
1001        const fileContentObj2 = {
1002          moduleInfo: {
1003            originSourceFilePath: 'file2.d.ts',
1004            buildFilePath: 'file2.d.ts',
1005            content: 'content2',
1006          },
1007          previousStageSourceMap: {},
1008        };
1009        fileContentManagerStub.getSortedFiles.returns(sortedFiles);
1010        fileContentManagerStub.fileNamesMap.set('file1.d.ts', 'file1.d.ts');
1011        fileContentManagerStub.fileNamesMap.set('file2.d.ts', 'file2.d.ts');
1012        fileContentManagerStub.readFileContent
1013          .withArgs('file1.d.ts').returns(fileContentObj1)
1014          .withArgs('file2.d.ts').returns(fileContentObj2);
1015        harFilesRecord.set('file2.d.ts',{});
1016        await reObfuscate(arkObfuscatorStub, harFilesRecord, printObfLogger, projectConfig);
1017        expect(harFilesRecord.has('file1.d.ts')).to.be.true;
1018        expect(harFilesRecord.get('file1.d.ts')).to.deep.equal({
1019          sourcePath: 'file1.d.ts',
1020          originalDeclarationCachePath: 'file1.d.ts',
1021          originalDeclarationContent: 'content1'
1022        });
1023        expect(harFilesRecord.has('file2.d.ts')).to.be.true;
1024        expect(harFilesRecord.get('file2.d.ts')).to.deep.equal({});
1025      });
1026
1027      mocha.it('10-5-2: should writeArkguardObfuscatedSourceCode if is not declaraiont file', async function () {
1028        const harFilesRecord = new Map();
1029        const logger = {};
1030        const projectConfig = {};
1031        const sortedFiles = ['file1.ts', 'file2.ts'];
1032        const fileContentObj1 = {
1033          moduleInfo: {
1034            originSourceFilePath: 'file1.ts',
1035            buildFilePath: 'file1.ts',
1036            content: 'content1',
1037          },
1038          previousStageSourceMap: {},
1039        };
1040        const fileContentObj2 = {
1041          moduleInfo: {
1042            originSourceFilePath: 'file2.ts',
1043            buildFilePath: 'file2.ts',
1044            content: 'content2',
1045          },
1046          previousStageSourceMap: {},
1047        };
1048        let writeArkguardObfuscatedSourceCodeStub = sinon.stub(arkUtils, 'writeArkguardObfuscatedSourceCode');
1049        fileContentManagerStub.getSortedFiles.returns(sortedFiles);
1050        fileContentManagerStub.fileNamesMap.set('file1.ts', 'file1.ts');
1051        fileContentManagerStub.fileNamesMap.set('file2.ts', 'file2.ts');
1052        fileContentManagerStub.readFileContent
1053          .withArgs('file1.ts').returns(fileContentObj1)
1054          .withArgs('file2.ts').returns(fileContentObj2);
1055        await reObfuscate(arkObfuscatorStub, harFilesRecord, printObfLogger, projectConfig);
1056        expect(writeArkguardObfuscatedSourceCodeStub.calledTwice).to.be.true;
1057      });
1058    });
1059  });
1060});