• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import * as fs from 'fs';
17import mocha from 'mocha';
18import { TimeAndMemInfo, TimeSumPrinter, TimeTracker, initPerformancePrinter } from '../../../src/utils/PrinterUtils';
19import { assert, expect } from 'chai';
20import { isFileExist } from '../../../src/initialization/utils';
21import {
22  blockPrinter,
23  endFilesEvent,
24  endSingleFileEvent,
25  performancePrinter,
26  printTimeSumData,
27  printTimeSumInfo,
28  startFilesEvent,
29  startSingleFileEvent
30} from '../../../src/ArkObfuscator';
31import type { IOptions } from '../../../src/configs/IOptions';
32const sinon = require('sinon');
33const DEFAULT_DURATION = 1; // Default time duration
34
35describe('test Cases for <PrinterUtils>.', function () {
36  beforeEach(() => {
37    performancePrinter.filesPrinter = new TimeTracker();
38    performancePrinter.singleFilePrinter = new TimeTracker();
39    performancePrinter.timeSumPrinter = new TimeSumPrinter();
40  });
41
42  describe('Tester Cases for <TimeTracker>.', function () {
43    let printer: TimeTracker;
44
45    beforeEach(() => {
46      printer = new TimeTracker();
47    })
48
49    describe('Tester Cases for <setOutputPath>.', function () {
50      /** test for setOutputPath */
51      it('Tester: <setOutputPath> case for TimeTracker#setOutputPath', function () {
52        let path = 'test/ut/utils/demo1.txt';
53        printer.setOutputPath(path);
54        let content: string = printer.getOutputPath();
55        assert.strictEqual(content, path);
56      });
57    });
58
59    describe('Tester Cases for <print>.', function () {
60      /** test for print */
61      it('Tester: <available outputPath> case for TimeTracker#print', function () {
62        let path = 'test/ut/utils/testTimeTrackerPrint.txt';
63        printer.setOutputPath(path);
64        printer.print('available outputPath case');
65        let content: string = fs.readFileSync(path, 'utf-8');
66        assert.strictEqual(content, 'available outputPath case\n');
67        fs.unlinkSync(path);
68      });
69
70      it('Tester: <unavailable outputPath> case for TimeTracker#print', function () {
71        let path = 'test/ut/utils/demo2.txt';
72        let message = 'unavailable outputPath case';
73        var spy = sinon.spy(console, 'log');
74        printer.print(message);
75        assert(spy.calledWith(message), message);
76        assert.strictEqual(isFileExist(path), false);
77        spy.restore();
78      });
79    });
80
81    describe('Tester Cases for <disablePrinter>.', function () {
82      /** test for print */
83      it('Tester: <empty output> case for TimeTracker#disablePrinter', function () {
84        const eventName = 'All files obfuscation';
85        let path = 'test/ut/utils/demo1.txt';
86        printer.setOutputPath(path);
87        printer.disablePrinter();
88        printer.getEventStack().set(eventName, { start: 0, duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0});
89        printer.endEvent(eventName);
90        let content: string = fs.readFileSync(path, 'utf-8');
91        const lines = content.split('\n');
92        const firstLine = lines[0].split(':');
93        const secondLine = lines[1].split(':');
94        const thirdLine = lines[2].split(':');
95        assert.strictEqual(firstLine[0], 'Obfuscation time cost');
96        assert.strictEqual(secondLine[0], 'Max time cost of single file');
97        assert.strictEqual(thirdLine[0], 'Max memory usage of single file');
98        fs.unlinkSync(path);
99      });
100    });
101
102    describe('Tester Cases for <startEvent>.', function () {
103      /** test for startEvent */
104      it('Tester: <start test event> case for TimeTracker#startEvent', function () {
105        let eventName = 'test event';
106        let path = 'test/ut/utils/testTimeTrackerPrint.txt';
107        let message = 'start test event';
108        printer.setOutputPath(path);
109        printer.startEvent(eventName, undefined, message);
110        const eventData = printer.getEventStack().get(eventName);
111        expect(eventData?.duration).to.equal(0);
112        expect(eventData?.endMemory).to.equal(0);
113        expect(eventData?.memoryUsage).to.equal(0);
114        assert.strictEqual(isFileExist(path), false);
115      });
116
117      it('Tester: <start create ast event> case for TimeTracker#startEvent', function () {
118        let eventName = 'Create AST';
119        printer.startEvent(eventName, undefined);
120        const eventData = printer.getEventStack().get(eventName);
121        expect(eventData?.duration).to.equal(0);
122        expect(eventData?.endMemory).to.equal(0);
123        expect(eventData?.memoryUsage).to.equal(0);
124      });
125    });
126
127    describe('Tester Cases for <endEvent>.', function () {
128      /** test for endEvent */
129      it('should throw an error if the event has not started', function () {
130        let eventName = '';
131        let path = 'test/ut/utils/demo1.txt';
132        printer.setOutputPath(path);
133        printer.startEvent('test event');
134        expect(() => printer.endEvent(eventName)).to.throw(`Event "${eventName}" not started`);
135      });
136
137      it('should calculate duration and memory usage correctly', () => {
138        const eventName = 'test Event';
139        printer.getEventStack().set(eventName,
140          { start: 0, duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0});
141        printer.endEvent(eventName);
142        const eventData = printer.getEventStack().get(eventName);
143        expect(eventData?.duration).to.not.equal(0);
144        expect(eventData?.endMemory).to.not.equal(0);
145        expect(eventData?.memoryUsage).to.not.equal(0);
146      });
147
148      it('should update filesTimeSum and maxTimeUsage when isFilesPrinter is true', () => {
149        const eventName = 'file Event';
150        const startMemory = process.memoryUsage().heapUsed;
151        printer.getEventStack().set(eventName,
152          { start: 0, duration: 0, startMemory: startMemory, endMemory: 0, memoryUsage: 0});
153        printer.endEvent(eventName, undefined, true);
154        expect(printer.getFilesTimeSum()).to.not.equal(0);
155        expect(printer.getMaxTimeUsage()).to.not.equal(0);
156        expect(printer.getMaxTimeFile()).to.equal(eventName);
157      });
158
159      it('should update maxMemoryUsage and maxMemoryFile when isFilesPrinter is true', () => {
160        const eventName = 'file Event';
161        const startTime = Date.now();
162        printer.getEventStack().set(eventName,
163          { start: startTime, duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0});
164        printer.endEvent(eventName, undefined, true);
165        expect(printer.getMaxMemoryUsage()).to.not.equal(0);
166        expect(printer.getMaxMemoryFile()).to.equal(eventName);
167      });
168
169      it('should output data and print max time and memory usage for ALL_FILES_OBFUSCATION', () => {
170        const eventName = 'All files obfuscation';
171        let path = 'test/ut/utils/demo1.txt';
172        printer.setOutputPath(path);
173        printer.getEventStack().set(eventName, { start: 0, duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0});
174        printer.endEvent(eventName);
175        let content: string = fs.readFileSync(path, 'utf-8');
176        const lines = content.split('\n');
177        const firstLine = lines[0].split(':');
178        const secondLine = lines[2].split(':');
179        const thirdLine = lines[3].split(':');
180        const fourthLine = lines[4].split(':');
181        assert.strictEqual(firstLine[0], '    All files obfuscation');
182        assert.strictEqual(secondLine[0], 'Obfuscation time cost');
183        assert.strictEqual(thirdLine[0], 'Max time cost of single file');
184        assert.strictEqual(fourthLine[0], 'Max memory usage of single file');
185        fs.unlinkSync(path);
186      });
187
188      it('should output data for CREATE_PRINTER', () => {
189        const eventName = 'Create Printer';
190        const startMemory = process.memoryUsage().heapUsed;
191        let path = 'test/ut/utils/demo1.txt';
192        printer.setOutputPath(path);
193        printer.getEventStack().set(eventName,
194          { start: Date.now(), duration: 0, startMemory: startMemory, endMemory: 0, memoryUsage: 0});
195        printer.endEvent(eventName, undefined, false, true);
196        let content: string = fs.readFileSync(path, 'utf-8');
197        const firstLine = content.split(':');
198        assert.strictEqual(firstLine[0], '        Create Printer');
199        fs.unlinkSync(path);
200      });
201
202      it('should get totalTime', () => {
203        let path = 'test/ut/utils/demo1.txt';
204        printer.setOutputPath(path);
205        const eventName1 = 'Obfuscation initialization';
206        const eventName2 = 'All files obfuscation';
207        let testFile = 'test/ut/utils/testFile.ts';
208        printer.getEventStack().set(eventName1,
209          { start: Date.now(), duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0});
210        printer.getEventStack().set(eventName2,
211          { start: Date.now(), duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0, filePath: testFile});
212        printer.endEvent(eventName2);
213        let content: string = fs.readFileSync(path, 'utf-8');
214        const lines = content.split('\n');
215        const firstLine = lines[0].split(':');
216        const secondLine = lines[1].split(':');
217        const thirdLine = lines[2].split(':');
218        assert.strictEqual(firstLine[0], 'Obfuscation time cost');
219        assert.strictEqual(secondLine[0], '    Obfuscation initialization');
220        assert.strictEqual(thirdLine[0], 'test/ut/utils/testFile.ts');
221        fs.unlinkSync(path);
222      });
223    });
224
225    describe('Tester Cases for <getCurrentEventData>.', function () {
226      it('should return a string with formatted event data', () => {
227        const eventName = 'test event';
228        printer.getEventStack().set(eventName,
229          { start: 0, duration: 10, startMemory: 1024, endMemory: 2048, memoryUsage: 1024});
230        const actualOutput: string = printer.getCurrentEventData();
231        const expectOutput: string = '        test event: timeCost:10.000 s startMemory:0.001MB endMemory:0.002MB memoryUsage:0.001MB\n';
232        expect(actualOutput).to.equal(expectOutput);
233      });
234    });
235
236    describe('Tester Cases for <getEventStack>', () => {
237
238      it('should return the event stack', () => {
239        printer.startEvent('test event');
240        const eventStack = printer.getEventStack();
241        expect(eventStack).to.have.keys(['test event']);
242        expect(eventStack.get('test event')?.start).to.closeTo(Date.now(), 10);
243        expect(eventStack.get('test event')?.duration).to.equal(0);
244        expect(eventStack.get('test event')?.endMemory).to.equal(0);
245        expect(eventStack.get('test event')?.memoryUsage).to.equal(0);
246      });
247    });
248  });
249
250
251  describe('Tester Cases for <TimeSumPrinter>.', function () {
252    let printer: TimeSumPrinter;
253
254    beforeEach(() => {
255      printer = new TimeSumPrinter();
256    })
257
258    describe('Tester Cases for <addEventDuration>.', function () {
259      /** test for addEventDuration */
260      it('should add duration to the event sum', function () {
261        printer.addEventDuration('test event1', 10);
262        printer.addEventDuration('test event2', 20);
263        printer.addEventDuration('test event1', 30);
264        const event1Duration = printer.getEventSum().get('test event1');
265        const event2Duration = printer.getEventSum().get('test event2');
266        expect(event1Duration).to.equal(40);
267        expect(event2Duration).to.equal(20);
268      });
269    });
270
271    describe('Tester Cases for <summarizeEventDuration>.', function () {
272      /** test for summarizeEventDuration */
273      it('should print the summarized event data', function () {
274        let path = 'test/ut/utils/demo1.txt';
275        printer.setOutputPath(path);
276        printer.addEventDuration('test event1', 10);
277        printer.addEventDuration('test event2', 20);
278        printer.addEventDuration('test event1', 30);
279        printer.summarizeEventDuration();
280        let content: string = fs.readFileSync(path, 'utf-8');
281        const expectOutput = "test event1: 40.000 s\ntest event2: 20.000 s\n\n";
282        expect(content).to.equal(expectOutput);
283        fs.unlinkSync(path);
284      });
285    });
286
287    describe('Tester Cases for <getCurrentEventData>.', function () {
288      it('should return a string with formatted event data', () => {
289        const eventName = 'test event';
290        printer.getEventSum().set(eventName, 10);
291        const actualOutput: string = printer.getCurrentEventData();
292        const expectOutput: string = 'test event: 10.000 s\n';
293        expect(actualOutput).to.equal(expectOutput);
294      });
295    });
296
297    describe('Tester Cases for <getEventSum>', () => {
298      it('should return the event sum', () => {
299        printer.addEventDuration('test event', 10);
300        const eventSum = printer.getEventSum();
301        expect(eventSum).to.have.keys(['test event']);
302        expect(eventSum.get('test event')).to.equal(10);
303      });
304    });
305  });
306
307  describe('Tester Cases for <initPerformancePrinter>', () => {
308    it('Printer config is not set', () => {
309      let mCustomProfiles: IOptions = {};
310      initPerformancePrinter(mCustomProfiles);
311      expect(performancePrinter.filesPrinter === undefined).to.be.true;
312      expect(performancePrinter.singleFilePrinter === undefined).to.be.true;
313      expect(performancePrinter.timeSumPrinter === undefined).to.be.true;
314    });
315
316    it('None of printers is enabled', () => {
317      let mCustomProfiles: IOptions = {
318        mPerformancePrinter: {
319          mFilesPrinter: false,
320          mSingleFilePrinter: false,
321          mSumPrinter: false
322        }
323      };
324      initPerformancePrinter(mCustomProfiles);
325      expect(performancePrinter.filesPrinter === undefined).to.be.true;
326      expect(performancePrinter.singleFilePrinter === undefined).to.be.true;
327      expect(performancePrinter.timeSumPrinter === undefined).to.be.true;
328    });
329
330    it('disable mFilesPrinter', () => {
331      let mCustomProfiles: IOptions = {
332        mPerformancePrinter: {
333          mFilesPrinter: false,
334          mSingleFilePrinter: true,
335          mSumPrinter: true,
336          mOutputPath: './log.txt'
337        }
338      };
339      initPerformancePrinter(mCustomProfiles);
340      expect(performancePrinter.filesPrinter?.isEnabled()).to.be.false;
341      expect(performancePrinter.singleFilePrinter?.isEnabled()).to.be.true;
342      expect(performancePrinter.timeSumPrinter?.isEnabled()).to.be.true;
343    });
344
345    it('disable mSingleFilePrinter', () => {
346      let mCustomProfiles: IOptions = {
347        mPerformancePrinter: {
348          mFilesPrinter: true,
349          mSingleFilePrinter: false,
350          mSumPrinter: true,
351          mOutputPath: './log.txt'
352        }
353      };
354      initPerformancePrinter(mCustomProfiles);
355      expect(performancePrinter.filesPrinter?.isEnabled()).to.be.true;
356      expect(performancePrinter.singleFilePrinter?.isEnabled()).to.be.false;
357      expect(performancePrinter.timeSumPrinter?.isEnabled()).to.be.true;
358    });
359
360    it('disable mSumPrinter', () => {
361      let mCustomProfiles: IOptions = {
362        mPerformancePrinter: {
363          mFilesPrinter: true,
364          mSingleFilePrinter: true,
365          mSumPrinter: false,
366          mOutputPath: './log.txt'
367        }
368      };
369      initPerformancePrinter(mCustomProfiles);
370      expect(performancePrinter.filesPrinter?.isEnabled()).to.be.true;
371      expect(performancePrinter.singleFilePrinter?.isEnabled()).to.be.true;
372      expect(performancePrinter.timeSumPrinter?.isEnabled()).to.be.false;
373    });
374  });
375
376  describe('Tester Cases for <blockPrinter>', () => {
377    it('should disable all printers', () => {
378      blockPrinter();
379      expect(performancePrinter.filesPrinter === undefined).to.be.true;
380      expect(performancePrinter.singleFilePrinter === undefined).to.be.true;
381      expect(performancePrinter.timeSumPrinter === undefined).to.be.true;
382    });
383  });
384
385  describe('Tester Cases for <startSingleFileEvent>', () => {
386    it('start a singleFile event', () => {
387      let eventName: string = 'newEvent';
388      let filePath: string = 'currentFile.ts';
389      startSingleFileEvent(eventName, undefined, filePath);
390      const eventStack: Map<string, TimeAndMemInfo> | undefined = performancePrinter.singleFilePrinter?.getEventStack();
391      let targetFilePath: string | undefined = eventStack?.get(eventName)?.filePath;
392      expect(targetFilePath === filePath).to.be.true;
393    });
394  });
395
396  describe('Tester Cases for <endSingleFileEvent>', () => {
397    it('end a singleFile event', () => {
398      let eventName: string = 'newEvent';
399      let filePath: string = 'currentFile.ts';
400      startSingleFileEvent(eventName, undefined, filePath);
401      endSingleFileEvent(eventName, undefined, false, false);
402      const eventStack: Map<string, TimeAndMemInfo> | undefined = performancePrinter.singleFilePrinter?.getEventStack();
403      let targetFilePath: string | undefined = eventStack?.get(eventName)?.filePath;
404      let memoryUsage: number | undefined = eventStack?.get(eventName)?.memoryUsage;
405      expect(targetFilePath === filePath).to.be.true;
406      expect(memoryUsage !== 0).to.be.true;
407    });
408  });
409
410  describe('Tester Cases for <startFilesEvent>', () => {
411    it('start a files event', () => {
412      let eventName: string = 'filesEvent';
413      let filePath: string = 'currentFile.ts';
414      startFilesEvent(eventName, undefined, filePath);
415      const eventStack: Map<string, TimeAndMemInfo> | undefined = performancePrinter.filesPrinter?.getEventStack();
416      let targetFilePath: string | undefined = eventStack?.get(eventName)?.filePath;
417      let startTime: number | undefined = eventStack?.get(eventName)?.start;
418      expect(targetFilePath === filePath).to.be.true;
419      expect(startTime !== 0).to.be.true;
420    });
421  });
422
423  describe('Tester Cases for <endFilesEvent>', () => {
424    it('end a files event', () => {
425      let eventName: string = 'filesEvent';
426      let filePath: string = 'currentFile.ts';
427      startFilesEvent(eventName, undefined, filePath);
428      endFilesEvent(eventName, undefined, false, false);
429      const eventStack: Map<string, TimeAndMemInfo> | undefined = performancePrinter.filesPrinter?.getEventStack();
430      let targetFilePath: string | undefined = eventStack?.get(eventName)?.filePath;
431      let memoryUsage: number | undefined = eventStack?.get(eventName)?.memoryUsage;
432      expect(targetFilePath === filePath).to.be.true;
433      expect(memoryUsage !== 0).to.be.true;
434    });
435  });
436
437  describe('Tester Cases for <printTimeSumInfo>', () => {
438    it('print input info of timeSumPrinter', () => {
439      let info: string = 'Info of timeSumPrinter';
440      let outputPath: string = 'test/ut/utils/outPutFile.txt';
441      performancePrinter.timeSumPrinter?.setOutputPath(outputPath);
442      printTimeSumInfo(info);
443      let content: string = fs.readFileSync(outputPath, 'utf-8');
444      expect(content === info + '\n').to.be.true;
445      fs.unlinkSync(outputPath);
446    });
447
448    it('timeSumPrinter is undefined', () => {
449      let info: string = 'Info of timeSumPrinter';
450      let outputPath: string = 'test/ut/utils/outPutFile.txt';
451      performancePrinter.timeSumPrinter?.setOutputPath(outputPath);
452      performancePrinter.timeSumPrinter = undefined;
453      printTimeSumInfo(info);
454      expect(fs.existsSync(outputPath)).to.be.false;
455    });
456  });
457
458  describe('Tester Cases for <printTimeSumData>', () => {
459    it('print data of timeSumPrinter', () => {
460      let outputPath: string = 'test/ut/utils/outPutFile.txt';
461      performancePrinter.timeSumPrinter?.setOutputPath(outputPath);
462      performancePrinter.timeSumPrinter?.addEventDuration('event1', DEFAULT_DURATION);
463      performancePrinter.timeSumPrinter?.addEventDuration('event1', DEFAULT_DURATION);
464      performancePrinter.timeSumPrinter?.addEventDuration('event2', DEFAULT_DURATION);
465      performancePrinter.timeSumPrinter?.addEventDuration('event2', DEFAULT_DURATION);
466      printTimeSumData();
467      let content: string = fs.readFileSync(outputPath, 'utf-8');
468      expect(content === 'event1: 2.000 s\nevent2: 2.000 s\n\n').to.be.true;
469      fs.unlinkSync(outputPath);
470    });
471
472    it('timeSumPrinter is undefined', () => {
473      let outputPath: string = 'test/ut/utils/outPutFile.txt';
474      performancePrinter.timeSumPrinter?.setOutputPath(outputPath);
475      performancePrinter.timeSumPrinter?.addEventDuration('event1', DEFAULT_DURATION);
476      performancePrinter.timeSumPrinter?.addEventDuration('event1', DEFAULT_DURATION);
477      performancePrinter.timeSumPrinter?.addEventDuration('event2', DEFAULT_DURATION);
478      performancePrinter.timeSumPrinter?.addEventDuration('event2', DEFAULT_DURATION);
479      performancePrinter.timeSumPrinter = undefined;
480      printTimeSumData();
481      expect(fs.existsSync(outputPath)).to.be.false;
482    });
483  });
484});
485
486
487
488
489