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 { TimeTracker, TimeSumPrinter } from '../../../src/utils/PrinterUtils';
19import { assert, expect } from 'chai';
20import { isFileExist } from '../../../src/initialization/utils';
21const sinon = require('sinon');
22
23describe('test Cases for <PrinterUtils>.', function () {
24  describe('Tester Cases for <TimeTracker>.', function () {
25    let printer: TimeTracker;
26
27    beforeEach(() => {
28      printer = new TimeTracker();
29    })
30
31    describe('Tester Cases for <setOutputPath>.', function () {
32      /** test for setOutputPath */
33      it('Tester: <setOutputPath> case for TimeTracker#setOutputPath', function () {
34        let path = 'test/ut/utils/demo1.txt';
35        printer.setOutputPath(path);
36        let content: string = printer.getOutputPath();
37        assert.strictEqual(content, path);
38      });
39    });
40
41    describe('Tester Cases for <print>.', function () {
42      /** test for print */
43      it('Tester: <available outputPath> case for TimeTracker#print', function () {
44        let path = 'test/ut/utils/testTimeTrackerPrint.txt';
45        printer.setOutputPath(path);
46        printer.print('available outputPath case');
47        let content: string = fs.readFileSync(path, 'utf-8');
48        assert.strictEqual(content, 'available outputPath case\n');
49        fs.unlinkSync(path);
50      });
51
52      it('Tester: <unavailable outputPath> case for TimeTracker#print', function () {
53        let path = 'test/ut/utils/demo2.txt';
54        let message = 'unavailable outputPath case';
55        var spy = sinon.spy(console, 'log');
56        printer.print(message);
57        assert(spy.calledWith(message), message);
58        assert.strictEqual(isFileExist(path), false);
59        spy.restore();
60      });
61    });
62
63    describe('Tester Cases for <startEvent>.', function () {
64      /** test for startEvent */
65      it('Tester: <start test event> case for TimeTracker#startEvent', function () {
66        let eventName = 'test event';
67        let path = 'test/ut/utils/testTimeTrackerPrint.txt';
68        let message = 'start test event';
69        printer.setOutputPath(path);
70        printer.startEvent(eventName, undefined, message);
71        const eventData = printer.getEventStack().get(eventName);
72        expect(eventData?.duration).to.equal(0);
73        expect(eventData?.endMemory).to.equal(0);
74        expect(eventData?.memoryUsage).to.equal(0);
75        assert.strictEqual(isFileExist(path), false);
76      });
77
78      it('Tester: <start create ast event> case for TimeTracker#startEvent', function () {
79        let eventName = 'Create AST';
80        let path = 'test/ut/utils/testTimeTrackerPrint.txt';
81        let message = 'start Create AST event';
82        printer.setOutputPath(path);
83        printer.startEvent(eventName, undefined, message);
84        let content: string = fs.readFileSync(path, 'utf-8');
85        const eventData = printer.getEventStack().get(eventName);
86        expect(eventData?.duration).to.equal(0);
87        expect(eventData?.endMemory).to.equal(0);
88        expect(eventData?.memoryUsage).to.equal(0);
89        assert.strictEqual(content, 'start Create AST event\n');
90        fs.unlinkSync(path);
91      });
92    });
93
94    describe('Tester Cases for <endEvent>.', function () {
95      /** test for endEvent */
96      it('should throw an error if the event has not started', function () {
97        let eventName = '';
98        let path = 'test/ut/utils/demo1.txt';
99        printer.setOutputPath(path);
100        printer.startEvent('test event');
101        expect(() => printer.endEvent(eventName)).to.throw(`Event "${eventName}" not started`);
102      });
103
104      it('should calculate duration and memory usage correctly', () => {
105        const eventName = 'test Event';
106        printer.getEventStack().set(eventName,
107          { start: 0, duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0});
108        printer.endEvent(eventName);
109        const eventData = printer.getEventStack().get(eventName);
110        expect(eventData?.duration).to.not.equal(0);
111        expect(eventData?.endMemory).to.not.equal(0);
112        expect(eventData?.memoryUsage).to.not.equal(0);
113      });
114
115      it('should update filesTimeSum and maxTimeUsage when isFilesPrinter is true', () => {
116        const eventName = 'file Event';
117        const startMemory = process.memoryUsage().heapUsed;
118        printer.getEventStack().set(eventName,
119          { start: 0, duration: 0, startMemory: startMemory, endMemory: 0, memoryUsage: 0});
120        printer.endEvent(eventName, undefined, true);
121        expect(printer.getFilesTimeSum()).to.not.equal(0);
122        expect(printer.getMaxTimeUsage()).to.not.equal(0);
123        expect(printer.getMaxTimeFile()).to.equal(eventName);
124      });
125
126      it('should update maxMemoryUsage and maxMemoryFile when isFilesPrinter is true', () => {
127        const eventName = 'file Event';
128        const startTime = Date.now();
129        printer.getEventStack().set(eventName,
130          { start: startTime, duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0});
131        printer.endEvent(eventName, undefined, true);
132        expect(printer.getMaxMemoryUsage()).to.not.equal(0);
133        expect(printer.getMaxMemoryFile()).to.equal(eventName);
134      });
135
136      it('should output data and print max time and memory usage for ALL_FILES_OBFUSCATION', () => {
137        const eventName = 'All files obfuscation';
138        let path = 'test/ut/utils/demo1.txt';
139        printer.setOutputPath(path);
140        printer.getEventStack().set(eventName, { start: 0, duration: 0, startMemory: 0, endMemory: 0, memoryUsage: 0});
141        printer.endEvent(eventName);
142        let content: string = fs.readFileSync(path, 'utf-8');
143        const lines = content.split('\n');
144        const firstLine = lines[0].split(':');
145        const secondLine = lines[2].split(':');
146        const thirdLine = lines[3].split(':');
147        assert.strictEqual(firstLine[0], 'All files obfuscation');
148        assert.strictEqual(secondLine[0], 'Max time cost');
149        assert.strictEqual(thirdLine[0], 'Max memory usage');
150        fs.unlinkSync(path);
151      });
152
153      it('should output data for CREATE_PRINTER', () => {
154        const eventName = 'Create Printer';
155        const startMemory = process.memoryUsage().heapUsed;
156        let path = 'test/ut/utils/demo1.txt';
157        printer.setOutputPath(path);
158        printer.getEventStack().set(eventName,
159          { start: Date.now(), duration: 0, startMemory: startMemory, endMemory: 0, memoryUsage: 0});
160        printer.endEvent(eventName);
161        let content: string = fs.readFileSync(path, 'utf-8');
162        const firstLine = content.split(':');
163        assert.strictEqual(firstLine[0], '    Create Printer');
164        fs.unlinkSync(path);
165      });
166    });
167
168    describe('Tester Cases for <getCurrentEventData>.', function () {
169      it('should return a string with formatted event data', () => {
170        const eventName = 'test event';
171        printer.getEventStack().set(eventName,
172          { start: 0, duration: 10, startMemory: 1024, endMemory: 2048, memoryUsage: 1024});
173        const actualOutput: string = printer.getCurrentEventData();
174        const expectOutput: string = 'test event: timeCost:10.000s startMemory:0.001MB endMemory:0.002MB memoryUsage:0.001MB\n';
175        expect(actualOutput).to.equal(expectOutput);
176      });
177    });
178
179    describe('Tester Cases for <getEventStack>', () => {
180
181      it('should return the event stack', () => {
182        printer.startEvent('test event');
183        const eventStack = printer.getEventStack();
184        expect(eventStack).to.have.keys(['test event']);
185        expect(eventStack.get('test event')?.start).to.closeTo(Date.now(), 10);
186        expect(eventStack.get('test event')?.duration).to.equal(0);
187        expect(eventStack.get('test event')?.endMemory).to.equal(0);
188        expect(eventStack.get('test event')?.memoryUsage).to.equal(0);
189      });
190    });
191  });
192
193
194  describe('Tester Cases for <TimeSumPrinter>.', function () {
195    let printer: TimeSumPrinter;
196
197    beforeEach(() => {
198      printer = new TimeSumPrinter();
199    })
200
201    describe('Tester Cases for <addEventDuration>.', function () {
202      /** test for addEventDuration */
203      it('should add duration to the event sum', function () {
204        printer.addEventDuration('test event1', 10);
205        printer.addEventDuration('test event2', 20);
206        printer.addEventDuration('test event1', 30);
207        const event1Duration = printer.getEventSum().get('test event1');
208        const event2Duration = printer.getEventSum().get('test event2');
209        expect(event1Duration).to.equal(40);
210        expect(event2Duration).to.equal(20);
211      });
212    });
213
214    describe('Tester Cases for <summarizeEventDuration>.', function () {
215      /** test for summarizeEventDuration */
216      it('should print the summarized event data', function () {
217        let path = 'test/ut/utils/demo1.txt';
218        printer.setOutputPath(path);
219        printer.addEventDuration('test event1', 10);
220        printer.addEventDuration('test event2', 20);
221        printer.addEventDuration('test event1', 30);
222        printer.summarizeEventDuration();
223        let content: string = fs.readFileSync(path, 'utf-8');
224        const expectOutput = "test event1: 40.000s\ntest event2: 20.000s\n\n";
225        expect(content).to.equal(expectOutput);
226        fs.unlinkSync(path);
227      });
228    });
229
230    describe('Tester Cases for <getCurrentEventData>.', function () {
231      it('should return a string with formatted event data', () => {
232        const eventName = 'test event';
233        printer.getEventSum().set(eventName, 10);
234        const actualOutput: string = printer.getCurrentEventData();
235        const expectOutput: string = 'test event: 10.000s\n';
236        expect(actualOutput).to.equal(expectOutput);
237      });
238    });
239
240    describe('Tester Cases for <getEventSum>', () => {
241      it('should return the event sum', () => {
242        printer.addEventDuration('test event', 10);
243        const eventSum = printer.getEventSum();
244        expect(eventSum).to.have.keys(['test event']);
245        expect(eventSum.get('test event')).to.equal(10);
246      });
247    });
248  });
249});
250
251
252
253
254