• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 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// Execute this file first to avoid circular dependency problems
17
18import { expect } from 'chai';
19import mocha from 'mocha';
20import fs, { unwatchFile } from "fs";
21import path from "path";
22import MagicString from 'magic-string';
23import sinon from 'sinon';
24
25import {
26  getBuildModeInLowerCase,
27  getPackageInfo,
28  genSourceMapFileName,
29  isOhModules,
30  isEs2Abc,
31  writeArkguardObfuscatedSourceCode,
32  writeMinimizedSourceCode,
33  tryMangleFileName,
34  getPreviousStageSourceMap,
35  collectObfuscationFileContent
36} from '../../lib/ark_utils';
37import {
38  DEBUG,
39  RELEASE,
40  OH_MODULES,
41  EXTNAME_TS,
42  EXTNAME_JS,
43  EXTNAME_ETS,
44  OBFUSCATION_TOOL
45} from '../../lib/fast_build/ark_compiler/common/ark_define';
46import RollUpPluginMock from './mock/rollup_mock/rollup_plugin_mock';
47import {
48  BUNDLE_NAME_DEFAULT,
49  ENTRY_MODULE_NAME_DEFAULT,
50  EXTNAME_MAP,
51  ENTRYABILITY_JS
52} from './mock/rollup_mock/common';
53import projectConfig from './utils/processProjectConfig';
54import {
55  ES2ABC,
56  TS2ABC
57} from '../../lib/pre_define';
58import { changeFileExtension } from '../../lib/fast_build/ark_compiler/utils';
59import ModuleSourceFileMock from './mock/class_mock/module_source_files_mock';
60import {
61  genTemporaryPath,
62  toUnixPath
63} from '../../lib/utils';
64import {
65  ObConfigResolver,
66  MergedConfig,
67  obfLogger
68} from '../../lib/fast_build/ark_compiler/common/ob_config_resolver';
69import {
70  utProcessArkConfig
71} from '../../lib/fast_build/ark_compiler/common/process_ark_config';
72import { ModuleSourceFile } from '../../lib/fast_build/ark_compiler/module/module_source_file';
73import { PROJECT_ROOT, TERSER_PROCESSED_EXPECTED_CODE } from './mock/rollup_mock/path_config';
74import { GEN_ABC_PLUGIN_NAME } from '../../lib/fast_build/ark_compiler/common/ark_define';
75import { SourceMapGenerator } from '../../lib/fast_build/ark_compiler/generate_sourcemap';
76import { ArkObfuscator } from 'arkguard';
77import {
78  ArkTSInternalErrorDescription,
79  ErrorCode
80} from '../../lib/fast_build/ark_compiler/error_code';
81import {
82  CommonLogger,
83  LogData,
84  LogDataFactory
85} from '../../lib/fast_build/ark_compiler/logger';
86import { initObfLogger, printObfLogger } from '../../lib/fast_build/ark_compiler/common/ob_config_resolver';
87import { getLogger } from 'log4js';
88import { createErrInfo } from './utils/utils';
89
90mocha.describe('test ark_utils file api', function () {
91  mocha.before(function () {
92    this.rollup = new RollUpPluginMock();
93  });
94
95  mocha.after(() => {
96    delete this.rollup;
97  });
98
99  mocha.it('1-1: test getBuildModeInLowerCase under build debug', function () {
100    this.rollup.build();
101    const buildMode = getBuildModeInLowerCase(this.rollup.share.projectConfig);
102    expect(buildMode === DEBUG).to.be.true;
103  });
104
105  mocha.it('1-2: test getBuildModeInLowerCase under build release', function () {
106    this.rollup.build(RELEASE);
107    const buildMode = getBuildModeInLowerCase(this.rollup.share.projectConfig);
108    expect(buildMode === RELEASE).to.be.true;
109  });
110
111  mocha.it('1-3: test getBuildModeInLowerCase under preview debug', function () {
112    this.rollup.preview();
113    const buildMode = getBuildModeInLowerCase(this.rollup.share.projectConfig);
114    expect(buildMode === DEBUG).to.be.true;
115  });
116
117  mocha.it('1-4: test getBuildModeInLowerCase under hot reload debug', function () {
118    this.rollup.hotReload();
119    const buildMode = getBuildModeInLowerCase(this.rollup.share.projectConfig);
120    expect(buildMode === DEBUG).to.be.true;
121  });
122
123  mocha.it('2-1: test getPackageInfo under build debug', function () {
124    this.rollup.build();
125    const returnInfo = getPackageInfo(this.rollup.share.projectConfig.aceModuleJsonPath);
126    expect(returnInfo[0] === BUNDLE_NAME_DEFAULT).to.be.true;
127    expect(returnInfo[1] === ENTRY_MODULE_NAME_DEFAULT).to.be.true;
128  });
129
130  mocha.it('2-2: test getPackageInfo under build release', function () {
131    this.rollup.build(RELEASE);
132    const returnInfo = getPackageInfo(this.rollup.share.projectConfig.aceModuleJsonPath);
133    expect(returnInfo[0] === BUNDLE_NAME_DEFAULT).to.be.true;
134    expect(returnInfo[1] === ENTRY_MODULE_NAME_DEFAULT).to.be.true;
135  });
136
137  mocha.it('2-3: test getPackageInfo under preview debug', function () {
138    this.rollup.preview();
139    const returnInfo = getPackageInfo(this.rollup.share.projectConfig.aceModuleJsonPath);
140    expect(returnInfo[0] === BUNDLE_NAME_DEFAULT).to.be.true;
141    expect(returnInfo[1] === ENTRY_MODULE_NAME_DEFAULT).to.be.true;
142  });
143
144  mocha.it('2-4: test getPackageInfo under hot reload debug', function () {
145    this.rollup.hotReload();
146    const returnInfo = getPackageInfo(this.rollup.share.projectConfig.aceModuleJsonPath);
147    expect(returnInfo[0] === BUNDLE_NAME_DEFAULT).to.be.true;
148    expect(returnInfo[1] === ENTRY_MODULE_NAME_DEFAULT).to.be.true;
149  });
150
151  mocha.it('3-1: test genSourceMapFileName under build debug', function () {
152    this.rollup.build();
153    for (const filePath of this.rollup.share.allFiles) {
154      if (filePath.endsWith(EXTNAME_TS) || filePath.endsWith(EXTNAME_JS)) {
155        const originPath = genSourceMapFileName(filePath);
156        const expectedPath = `${filePath}${EXTNAME_MAP}`;
157        expect(originPath === expectedPath).to.be.true;
158      } else if (filePath.endsWith(EXTNAME_ETS)) {
159        const originPath = genSourceMapFileName(filePath);
160        expect(originPath === filePath).to.be.true;
161      }
162    }
163  });
164
165  mocha.it('3-2: test genSourceMapFileName under build release', function () {
166    this.rollup.build(RELEASE);
167    for (const filePath of this.rollup.share.allFiles) {
168      if (filePath.endsWith(EXTNAME_TS) || filePath.endsWith(EXTNAME_JS)) {
169        const originPath = genSourceMapFileName(filePath);
170        const expectedPath = `${filePath}${EXTNAME_MAP}`;
171        expect(originPath === expectedPath).to.be.true;
172      }
173    }
174  });
175
176  mocha.it('3-3: test genSourceMapFileName under preview debug', function () {
177    this.rollup.preview();
178    for (const filePath of this.rollup.share.allFiles) {
179      if (filePath.endsWith(EXTNAME_TS) || filePath.endsWith(EXTNAME_JS)) {
180        const originPath = genSourceMapFileName(filePath);
181        const expectedPath = `${filePath}${EXTNAME_MAP}`;
182        expect(originPath === expectedPath).to.be.true;
183      }
184    }
185  });
186
187  mocha.it('3-4: test genSourceMapFileName under hot reload debug', function () {
188    this.rollup.hotReload();
189    for (const filePath of this.rollup.share.allFiles) {
190      if (filePath.endsWith(EXTNAME_TS) || filePath.endsWith(EXTNAME_JS)) {
191        const originPath = genSourceMapFileName(filePath);
192        const expectedPath = `${filePath}${EXTNAME_MAP}`;
193        expect(originPath === expectedPath).to.be.true;
194      }
195    }
196  });
197
198  mocha.it('4-1: test isOhModules under build debug', function () {
199    this.rollup.build();
200    const returnInfo = isOhModules(this.rollup.share.projectConfig);
201    expect(returnInfo === false).to.be.true;
202    this.rollup.share.projectConfig.packageDir = OH_MODULES;
203    const returnInfoOh = isOhModules(this.rollup.share.projectConfig);
204    expect(returnInfoOh).to.be.true;
205  });
206
207  mocha.it('4-2: test isOhModules under build release', function () {
208    this.rollup.build(RELEASE);
209    const returnInfo = isOhModules(this.rollup.share.projectConfig);
210    expect(returnInfo === false).to.be.true;
211    this.rollup.share.projectConfig.packageDir = OH_MODULES;
212    const returnInfoOh = isOhModules(this.rollup.share.projectConfig);
213    expect(returnInfoOh).to.be.true;
214  });
215
216  mocha.it('4-3: test isOhModules under preview debug', function () {
217    this.rollup.preview();
218    const returnInfo = isOhModules(this.rollup.share.projectConfig);
219    expect(returnInfo === false).to.be.true;
220    this.rollup.share.projectConfig.packageDir = OH_MODULES;
221    const returnInfoOh = isOhModules(this.rollup.share.projectConfig);
222    expect(returnInfoOh).to.be.true;
223  });
224
225  mocha.it('4-4: test isOhModules under hot reload debug', function () {
226    this.rollup.hotReload();
227    const returnInfo = isOhModules(this.rollup.share.projectConfig);
228    expect(returnInfo === false).to.be.true;
229    this.rollup.share.projectConfig.packageDir = OH_MODULES;
230    const returnInfoOh = isOhModules(this.rollup.share.projectConfig);
231    expect(returnInfoOh).to.be.true;
232  });
233
234  mocha.it('4-5: test isOhModules under hot fix debug', function () {
235    projectConfig.buildMode = DEBUG;
236    const returnInfo = isOhModules(projectConfig);
237    expect(returnInfo).to.be.true;
238  });
239
240  mocha.it('4-6: test isOhModules under hot fix release', function () {
241    projectConfig.buildMode = RELEASE;
242    const returnInfo = isOhModules(projectConfig);
243    expect(returnInfo).to.be.true;
244  });
245
246  mocha.it('5-1: test isEs2Abc under build debug', function () {
247    this.rollup.build();
248    this.rollup.share.projectConfig.pandaMode = ES2ABC;
249    const returnInfo = isEs2Abc(this.rollup.share.projectConfig);
250    expect(returnInfo).to.be.true;
251
252    this.rollup.share.projectConfig.pandaMode = TS2ABC;
253    const returnInfoTS2ABC = isEs2Abc(this.rollup.share.projectConfig);
254    expect(returnInfoTS2ABC === false).to.be.true;
255
256    this.rollup.share.projectConfig.pandaMode = "undefined";
257    const returnInfoUndef = isEs2Abc(this.rollup.share.projectConfig);
258    expect(returnInfoUndef).to.be.true;
259
260    this.rollup.share.projectConfig.pandaMode = undefined;
261    const returnInfoUndefined = isEs2Abc(this.rollup.share.projectConfig);
262    expect(returnInfoUndefined).to.be.true;
263  });
264
265  mocha.it('5-2: test isEs2Abc under build release', function () {
266    this.rollup.build(RELEASE);
267    this.rollup.share.projectConfig.pandaMode = ES2ABC;
268    const returnInfo = isEs2Abc(this.rollup.share.projectConfig);
269    expect(returnInfo).to.be.true;
270
271    this.rollup.share.projectConfig.pandaMode = TS2ABC;
272    const returnInfoTS2ABC = isEs2Abc(this.rollup.share.projectConfig);
273    expect(returnInfoTS2ABC).to.be.false;
274  });
275
276  mocha.it('5-3: test isEs2Abc under preview debug', function () {
277    this.rollup.preview();
278    this.rollup.share.projectConfig.pandaMode = ES2ABC;
279    const returnInfo = isEs2Abc(this.rollup.share.projectConfig);
280    expect(returnInfo).to.be.true;
281
282    this.rollup.share.projectConfig.pandaMode = TS2ABC;
283    const returnInfoTS2ABC = isEs2Abc(this.rollup.share.projectConfig);
284    expect(returnInfoTS2ABC).to.be.false;
285  });
286
287  mocha.it('5-4: test isEs2Abc under hot reload debug', function () {
288    this.rollup.hotReload();
289    this.rollup.share.projectConfig.pandaMode = ES2ABC;
290    const returnInfo = isEs2Abc(this.rollup.share.projectConfig);
291    expect(returnInfo).to.be.true;
292
293    this.rollup.share.projectConfig.pandaMode = TS2ABC;
294    const returnInfoTS2ABC = isEs2Abc(this.rollup.share.projectConfig);
295    expect(returnInfoTS2ABC).to.be.false;
296  });
297
298  mocha.it('5-5: test isEs2Abc under hot fix debug', function () {
299    projectConfig.buildMode = DEBUG;
300    projectConfig.pandaMode = ES2ABC;
301    const returnInfo = isEs2Abc(projectConfig);
302    expect(returnInfo).to.be.true;
303
304    projectConfig.pandaMode = TS2ABC;
305    const returnInfoTS2ABC = isEs2Abc(projectConfig);
306    expect(returnInfoTS2ABC).to.be.false;
307  });
308
309  mocha.it('5-6: test isEs2Abc under hot fix release', function () {
310    projectConfig.buildMode = RELEASE;
311    projectConfig.pandaMode = ES2ABC;
312    const returnInfo = isEs2Abc(projectConfig);
313    expect(returnInfo).to.be.true;
314
315    projectConfig.pandaMode = TS2ABC;
316    const returnInfoTS2ABC = isEs2Abc(projectConfig);
317    expect(returnInfoTS2ABC).to.be.false;
318  });
319
320  mocha.it('6-1: test the error message of writeArkguardObfuscatedSourceCode', async function () {
321    this.rollup.build(RELEASE);
322    SourceMapGenerator.initInstance(this.rollup);
323    this.rollup.share.getHvigorConsoleLogger = undefined;
324    initObfLogger(this.rollup.share);
325    const stub = sinon.stub(obfLogger, 'error');
326    const red: string = '\x1B[31m';
327    try {
328      await writeArkguardObfuscatedSourceCode(
329        {content: undefined, buildFilePath: '', relativeSourceFilePath: '', originSourceFilePath: ''},
330        printObfLogger, this.rollup.share.projectConfig, {});
331    } catch (e) {
332    }
333    expect(stub.calledWith(red,
334      `ArkTS:INTERNAL ERROR: Failed to obfuscate file '' with arkguard. TypeError: Cannot read properties of undefined (reading 'obfuscate')`
335    )).to.be.true;
336    stub.restore();
337    SourceMapGenerator.cleanSourceMapObject();
338  });
339
340  mocha.it('6-2: test the error message of writeArkguardObfuscatedSourceCode' +
341    'with getHvigorConsoleLogger', async function () {
342    this.rollup.build(RELEASE);
343    SourceMapGenerator.initInstance(this.rollup);
344    class customShare {
345      public getHvigorConsoleLogger(prefix: string) {
346       const logger = hvigorLogger.getLogger(prefix);
347       return logger;
348     }
349    }
350    class hvigorLogger {
351      mSubSystem: string = '';
352      constructor(subSystem: string) {
353        this.mSubSystem = subSystem;
354      }
355
356      public printError(errInfo: Object) {
357      }
358
359      public static getLogger(subSystem): hvigorLogger {
360        return new hvigorLogger(subSystem);
361      }
362    }
363    initObfLogger(new customShare());
364    const stub = sinon.stub(obfLogger, 'printError');
365    try {
366      await writeArkguardObfuscatedSourceCode(
367        {content: undefined, buildFilePath: '', relativeSourceFilePath: '', originSourceFilePath: ''},
368        printObfLogger, this.rollup.share.projectConfig, {});
369    } catch (e) {
370    }
371    const info = {
372        code: '10810001',
373        description: 'ArkTS compiler Error',
374        cause: "ArkTS:INTERNAL ERROR: Failed to obfuscate file '' with arkguard. TypeError: Cannot read properties of undefined (reading 'obfuscate')",
375        position: '',
376        solutions: [ 'Please modify the code based on the error information.' ]
377    };
378    expect(stub.calledWith(info)).to.be.true;
379    stub.restore();
380    SourceMapGenerator.cleanSourceMapObject();
381  });
382
383  mocha.it('7-1: test the error message of writeMinimizedSourceCode', async function () {
384    this.rollup.build(RELEASE);
385    const errInfo: LogData = LogDataFactory.newInstance(
386      ErrorCode.ETS2BUNDLE_INTERNAL_SOURCE_CODE_OBFUSCATION_FAILED,
387      ArkTSInternalErrorDescription,
388      'Failed to obfuscate source code for filePath'
389    );
390    const logger = CommonLogger.getInstance(this.rollup);
391    const stub = sinon.stub(logger.getLoggerFromErrorCode(errInfo.code), 'printError');
392    try {
393      await writeMinimizedSourceCode(undefined, 'filePath', logger);
394    } catch (e) {
395    }
396    expect(stub.calledWith(errInfo)).to.be.true;
397    stub.restore();
398  });
399
400  mocha.it('7-2: test the error message of writeMinimizedSourceCode without getHvigorConsoleLogger', async function () {
401    this.rollup.build(RELEASE);
402    const errInfo: LogData = LogDataFactory.newInstance(
403      ErrorCode.ETS2BUNDLE_INTERNAL_SOURCE_CODE_OBFUSCATION_FAILED,
404      ArkTSInternalErrorDescription,
405      'Failed to obfuscate source code for filePath'
406    );
407    CommonLogger.destroyInstance();
408    const getHvigorConsoleLogger = this.rollup.share.getHvigorConsoleLogger;
409    this.rollup.share.getHvigorConsoleLogger = undefined;
410    const logger = CommonLogger.getInstance(this.rollup);
411    const stub = sinon.stub(logger.logger, 'error');
412    try {
413      await writeMinimizedSourceCode(undefined, 'filePath', logger);
414    } catch (e) {
415    }
416    expect(stub.calledWith(errInfo.toString())).to.be.true;
417    CommonLogger.destroyInstance();
418    this.rollup.share.getHvigorConsoleLogger = getHvigorConsoleLogger;
419    stub.restore();
420  });
421
422  mocha.it('8-1: test tryMangleFileName when obfuscation is disabled', async function () {
423    const filePath = '/mnt/application/entry/build/default/cache/default/default@CompileArkTS/esmodule/release/src/main/ets/entryability/EntryAbility.ts';
424    const originalFilePath = '/mnt/application/entry/src/main/ets/entryability/EntryAbility.ets';
425    const projectConfig = {
426      projectRootPath: '/mnt/application',
427      packageDir: 'oh_modules',
428      modulePathMap: {
429        entry: '/mnt/application/entry'
430      },
431      obfuscationMergedObConfig: {
432        options: {
433          enableFileNameObfuscation: false
434        }
435      }
436    }
437    const result = tryMangleFileName(filePath, projectConfig, originalFilePath);
438    expect(result === filePath).to.be.true;
439  });
440
441  mocha.it('8-2: test tryMangleFileName when obfuscation is enabled', async function () {
442    const filePath = '/mnt/application/entry/build/default/cache/default/default@CompileArkTS/esmodule/release/src/main/ets/entryability/EntryAbility.ts';
443    const originalFilePath = '/mnt/application/entry/src/main/ets/entryability/EntryAbility.ets';
444    const newFilePath = '/mnt/application/entry/build/default/cache/default/default@CompileArkTS/esmodule/release/src/main/ets/a/b.ts';
445    const projectConfig = {
446      projectRootPath: '/mnt/application',
447      packageDir: 'oh_modules',
448      modulePathMap: {
449        entry: '/mnt/application/entry'
450      },
451      obfuscationMergedObConfig: {
452        options: {
453          enableFileNameObfuscation: true
454        }
455      }
456    }
457
458    const printerConfig = {
459      //Print obfuscation time&memory usage of all files and obfuscation processes
460      mFilesPrinter: false,
461      //Print time&memory usage of a single file obfuscation in transform processes
462      mSingleFilePrinter: false,
463      //Print sum up time of transform processes during obfuscation
464      mSumPrinter: false,
465      //Output path of printer
466      mOutputPath: ""
467    }
468
469    const arkguardConfig = {
470      mRenameFileName: {
471        mEnable: true,
472        mNameGeneratorType: 1,
473        mReservedFileNames: [
474          'entry',
475          'mnt',
476          'application',
477          'entry',
478          'src',
479          'main',
480          'ets',
481          'build',
482          'default',
483          'cache',
484          'default',
485          'default@CompileArkTS',
486          'esmodule',
487          'release'
488        ],
489      },
490      mPerformancePrinter: printerConfig
491    }
492
493    let arkObfuscator: ArkObfuscator = new ArkObfuscator();
494    arkObfuscator.init(arkguardConfig);
495    const content = `function foo() {}`
496    const obfuscateResult = arkObfuscator.obfuscate(content, filePath, undefined);
497    obfuscateResult.then(result => {
498      const afterObfuscateFilePath = result.filePath;
499      expect(afterObfuscateFilePath === newFilePath).to.be.true;
500    })
501
502    const result = tryMangleFileName(filePath, projectConfig, originalFilePath);
503    expect(result === newFilePath).to.be.true;
504  });
505
506  mocha.it('9-1: test writeArkguardObfuscatedSourceCode when obfuscation is enabled', async function () {
507    this.rollup.build(RELEASE);
508    const logger = this.rollup.share.getLogger(GEN_ABC_PLUGIN_NAME);
509    const arkguardConfig = {
510      mCompact: false,
511      mDisableConsole: false,
512      mSimplify: false,
513      mRemoveComments: true,
514      mNameObfuscation: {
515        mEnable: true,
516        mNameGeneratorType: 1,
517        mReservedNames: [],
518        mRenameProperties: false,
519        mReservedProperties: [],
520        mKeepStringProperty: true,
521        mTopLevel: false,
522        mReservedToplevelNames: [],
523        mUniversalReservedProperties: [],
524        mUniversalReservedToplevelNames: [],
525      },
526      mRemoveDeclarationComments: {
527        mEnable: true,
528        mReservedComments: []
529      },
530      mEnableSourceMap: true,
531      mEnableNameCache: true,
532      mRenameFileName: {
533        mEnable: false,
534        mNameGeneratorType: 1,
535        mReservedFileNames: [],
536      },
537      mExportObfuscation: false,
538      mPerformancePrinter: {
539        mFilesPrinter: false,
540        mSingleFilePrinter: false,
541        mSumPrinter: false,
542        mOutputPath: ""
543      },
544      mKeepFileSourceCode: {
545        mKeepSourceOfPaths: new Set(),
546        mkeepFilesAndDependencies: new Set(),
547      },
548    };
549
550    const sourceMapGenerator: SourceMapGenerator = SourceMapGenerator.initInstance(this.rollup);
551    sourceMapGenerator.setNewSoureMaps(false);
552    const arkObfuscator: ArkObfuscator = new ArkObfuscator();
553    arkObfuscator.init(arkguardConfig);
554
555    const projectConfig = {
556      projectRootPath: PROJECT_ROOT,
557      arkObfuscator: arkObfuscator,
558      packageDir: 'oh_modules',
559      localPackageSet: new Set(),
560      useTsHar: false,
561      useNormalized: false
562    };
563
564    const sourceFileName = 'sourceFile.ts';
565    const originalSourceFilePath = path.join(__dirname, '../../test/ark_compiler_ut/testdata/har_obfuscation', sourceFileName);
566    const moduleInfo = {
567      content: fs.readFileSync(originalSourceFilePath, 'utf-8'),
568      buildFilePath: `${PROJECT_ROOT}/har_obfuscation/build/default/cache/${sourceFileName}`,
569      relativeSourceFilePath: `har_obfuscation/${sourceFileName}`,
570      originSourceFilePath: originalSourceFilePath,
571      rollupModuleId: originalSourceFilePath
572    };
573
574    try {
575      await writeArkguardObfuscatedSourceCode(moduleInfo, logger, projectConfig, undefined);
576    } catch (e) {
577    }
578    const expectedResult = `export function add(d: number, e: number): number {
579    return d + e;
580}
581export function findElement<a>(b: a[], c: (item: a) => boolean): a | undefined {
582    return b.find(c);
583}
584`;
585    const result = fs.readFileSync(moduleInfo.buildFilePath, 'utf-8');
586    expect(result === expectedResult).to.be.true;
587
588    const declFileName = 'sourceFile.d.ts';
589    const originalDeclFilePath = path.join(__dirname, '../../test/ark_compiler_ut/testdata/har_obfuscation/', declFileName);
590
591    const declModuleInfo = {
592      content: fs.readFileSync(originalDeclFilePath, 'utf-8'),
593      buildFilePath: `${PROJECT_ROOT}/har_obfuscation/build/default/cache/${declFileName}`,
594      relativeSourceFilePath: `har_obfuscation/build/default/cache/${declFileName}`,
595      originSourceFilePath: originalSourceFilePath,
596      rollupModuleId: originalSourceFilePath
597    };
598
599    try {
600      await writeArkguardObfuscatedSourceCode(declModuleInfo, logger, projectConfig, undefined);
601    } catch (e) {
602    }
603
604    const expectedDeclResult = `export declare function add(d: number, e: number): number;
605export declare function findElement<a>(b: a[], c: (item: a) => boolean): a | undefined;
606`;
607    const declResult = fs.readFileSync(declModuleInfo.buildFilePath, 'utf-8');
608    expect(declResult === expectedDeclResult).to.be.true;
609  });
610
611  mocha.describe('10: test getPreviousStageSourceMap', function() {
612    let sourceMapGeneratorStub;
613    mocha.beforeEach(function () {
614      sourceMapGeneratorStub = sinon.stub(SourceMapGenerator, 'getInstance');
615    });
616
617    mocha.afterEach(() => {
618      sinon.restore();
619    });
620
621    mocha.it('10-1: should return undefined if relativeSourceFilePath is empty', async function () {
622      const moduleInfo = {
623        buildFilePath: 'file.js',
624        relativeSourceFilePath: '',
625        rollupModuleId: 'moduleId'
626      };
627      const result = getPreviousStageSourceMap(moduleInfo);
628      expect(result).to.be.undefined;
629    });
630
631    mocha.it('10-2: should return undefined if the file is a declaration file', function() {
632      const moduleInfo = {
633        buildFilePath: 'file.d.ts',
634        relativeSourceFilePath: 'sourceFile.ts',
635        rollupModuleId: 'moduleId'
636      };
637      const result = getPreviousStageSourceMap(moduleInfo);
638      expect(result).to.be.undefined;
639    });
640
641    mocha.it('10-3: should call getSpecifySourceMap with rollupModuleId if isNewSourceMaps is true', function() {
642      const fakeSourceMap = {};
643      const instanceStub = {
644        isNewSourceMaps: sinon.stub().returns(true),
645        getSpecifySourceMap: sinon.stub().returns(fakeSourceMap)
646      };
647      sourceMapGeneratorStub.returns(instanceStub);
648
649      const moduleInfo = {
650        buildFilePath: 'file.js',
651        relativeSourceFilePath: 'sourceFile.ts',
652        rollupModuleId: 'moduleId'
653      };
654      const result = getPreviousStageSourceMap(moduleInfo);
655
656      expect(instanceStub.getSpecifySourceMap.calledWith({}, 'moduleId')).to.be.true;
657      expect(result).to.equal(fakeSourceMap);
658    });
659
660    mocha.it('10-4: should call getSpecifySourceMap with relativeSourceFilePath if isNewSourceMaps is false', function() {
661      const fakeSourceMap = {};
662      const instanceStub = {
663        isNewSourceMaps: sinon.stub().returns(false),
664        getSpecifySourceMap: sinon.stub().returns(fakeSourceMap)
665      };
666      sourceMapGeneratorStub.returns(instanceStub);
667
668      const moduleInfo = {
669        buildFilePath: 'file.js',
670        relativeSourceFilePath: 'sourceFile.ts',
671        rollupModuleId: 'moduleId'
672      };
673      const result = getPreviousStageSourceMap(moduleInfo);
674
675      expect(instanceStub.getSpecifySourceMap.calledWith({}, 'sourceFile.ts')).to.be.true;
676      expect(result).to.equal(fakeSourceMap);
677    });
678  })
679  mocha.describe('11: test collectObfuscationFileContent', function () {
680    let fileContentManagerStub;
681
682    mocha.beforeEach(function () {
683      fileContentManagerStub = {
684        updateFileContent: sinon.stub(),
685      };
686    });
687
688    mocha.afterEach(function () {
689      sinon.restore();
690    });
691
692    mocha.it('11-1: should not call updateFileContent if filePathManager is not defined', function () {
693      const moduleInfo = {
694        buildFilePath: 'file.js',
695        originSourceFilePath: 'sourceFile.ts',
696      };
697      const projectConfig = {
698        arkObfuscator: {},
699      };
700      const previousStageSourceMap = {};
701
702      collectObfuscationFileContent(moduleInfo, projectConfig, previousStageSourceMap);
703
704      expect(fileContentManagerStub.updateFileContent.called).to.be.false;
705    });
706
707    mocha.it('11-2: should not call updateFileContent if the file is a declaration file and not an original declaration file', function () {
708      const moduleInfo = {
709        buildFilePath: 'file.d.ts',
710        originSourceFilePath: 'sourceFile.ts',
711      };
712      const projectConfig = {
713        arkObfuscator: {
714          filePathManager: {},
715          fileContentManager: fileContentManagerStub,
716        },
717      };
718      const previousStageSourceMap = {};
719
720      collectObfuscationFileContent(moduleInfo, projectConfig, previousStageSourceMap);
721
722      expect(fileContentManagerStub.updateFileContent.called).to.be.false;
723    });
724
725    mocha.it('11-3: should call updateFileContent if the file is not a declaration file', function () {
726      const moduleInfo = {
727        buildFilePath: 'file.js',
728        originSourceFilePath: 'sourceFile.ts',
729      };
730      const projectConfig = {
731        arkObfuscator: {
732          filePathManager: {},
733          fileContentManager: fileContentManagerStub,
734        },
735      };
736      const previousStageSourceMap = {};
737
738      collectObfuscationFileContent(moduleInfo, projectConfig, previousStageSourceMap);
739
740      expect(fileContentManagerStub.updateFileContent.calledOnce).to.be.true;
741      expect(fileContentManagerStub.updateFileContent.calledWith({
742        moduleInfo: moduleInfo,
743        previousStageSourceMap: previousStageSourceMap,
744      })).to.be.true;
745    });
746
747    mocha.it('11-4: should call updateFileContent if the file is an original declaration file', function () {
748      const moduleInfo = {
749        buildFilePath: 'file.d.ts',
750        originSourceFilePath: 'file.d.ts',
751      };
752      const projectConfig = {
753        arkObfuscator: {
754          filePathManager: {},
755          fileContentManager: fileContentManagerStub,
756        },
757      };
758      const previousStageSourceMap = {};
759
760      collectObfuscationFileContent(moduleInfo, projectConfig, previousStageSourceMap);
761
762      expect(fileContentManagerStub.updateFileContent.calledOnce).to.be.true;
763      expect(fileContentManagerStub.updateFileContent.calledWith({
764        moduleInfo: moduleInfo,
765        previousStageSourceMap: previousStageSourceMap,
766      })).to.be.true;
767    });
768  });
769});