• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * Copyright (c) 2024-2025 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
16class Test {
17    constructor(numCheckpoints: int) {
18        this.numCheckpoints = numCheckpoints;
19        this.sequence = new Array<number>();
20    }
21
22    check(): boolean {
23        if (this.result == Test.RESULT_FAILED) {
24            return false;
25        }
26        if (this.sequence.length != this.numCheckpoints) {
27            console.log("Test failed. Expected " + this.numCheckpoints + " checkpoints, but got " + this.sequence.length);
28            this.result = Test.RESULT_FAILED;
29            return false;
30        }
31        for (let i = 0; i < this.sequence.length; ++i) {
32            if (this.sequence[i] != i) {
33                console.log("Test failed. Expected " + i + "-th checkpoint to be " + i + ", but got " + this.sequence[i]);
34                this.result = Test.RESULT_FAILED;
35                return false;
36            }
37        }
38        return true;
39    }
40
41    fail(message: string): void {
42        this.result = Test.RESULT_FAILED;
43        console.log(message);
44    }
45
46    checkpoint(value: int) {
47        this.sequence.push(value);
48    }
49
50    private static RESULT_UNSET: int = 0;
51    private static RESULT_PASSED: int = 1;
52    private static RESULT_FAILED: int = 2;
53
54    result: int = Test.RESULT_UNSET;
55    failMessage: string = "";
56    private sequence: Array<number>;
57    private numCheckpoints: int;
58}
59
60function check(): boolean {
61    return globalTest!.check();
62}
63
64let globalTest: Test | null = null;
65
66function testSetTimeout(): void {
67    globalTest = new Test(3);
68    let sequence = new Array<number>();
69    let delay = 100;
70    globalTest!.checkpoint(0);
71    let start = Date.now();
72    setTimeout((): void => {
73        // To get time Date.now and libuv uses clock_gettime under the hood, but with different parameters. Date.now() uses CLOCK_REALTIME, but libuv uses CLOCK_MONOTONIC.
74        // When we calculate time interval there may be an error. For example time interval measured by Date.now may be 5.9ms round to 5
75        // and time interval measured by libuv is 6.1 round to 6.
76        // To avoid such error just add +1 to time interval.
77        let spentTime = Date.now() - start + 1;
78        if (spentTime < delay) {
79            globalTest!.fail("The callback is called after " + spentTime + "ms. Expected to be called after " + delay + "ms at least.");
80        }
81        globalTest!.checkpoint(2);
82    }, delay);
83    globalTest!.checkpoint(1);
84}
85
86function testClearTimeout(): void {
87    globalTest = new Test(2);
88    let sequence = new Array<number>();
89    globalTest!.checkpoint(0);
90    let timerId = setTimeout((): void => {
91        globalTest!.fail("The callback should not be called.");
92    }, 0);
93    clearTimeout(timerId);
94    globalTest!.checkpoint(1);
95}
96
97function testSetInterval(): void {
98    globalTest = new Test(6);
99    let sequence = new Array<number>();
100    let delay = 100;
101    let checkpoint = 2;
102    globalTest!.checkpoint(0);
103    let start = Date.now();
104    let timerId: number;
105    timerId = setInterval((): void => {
106        // To get time Date.now and libuv uses clock_gettime under the hood, but with different parameters. Date.now() uses CLOCK_REALTIME, but libuv uses CLOCK_MONOTONIC.
107        // When we calculate time interval there may be an error. For example time interval measured by Date.now may be 5.9ms round to 5
108        // and time interval measured by libuv is 6.1 round to 6.
109        // To avoid such error just add +1 to time interval.
110        let spentTime = Date.now() - start + 1;
111        if (spentTime < delay) {
112            globalTest!.fail("The callback is called after " + spentTime + "ms. Expected to be called after " + delay + "ms at least.");
113        }
114        if (checkpoint == 5) {
115            clearInterval(timerId);
116        }
117        globalTest!.checkpoint(checkpoint);
118        ++checkpoint;
119    }, delay);
120    globalTest!.checkpoint(1);
121}
122
123function testSetTimeoutExecuteOrder() : void {
124    globalTest = new Test(6);
125    globalTest!.checkpoint(0);
126    setTimeout((): void => {
127        globalTest!.checkpoint(2);
128    }, 1);
129    let now = Date.now();
130    while(Date.now() - now < 2) {}
131    setTimeout((): void => {
132        globalTest!.checkpoint(3);
133    }, 0);
134    setTimeout((): void => {
135        globalTest!.checkpoint(4);
136    }, 0);
137    setTimeout((): void => {
138        globalTest!.checkpoint(5);
139    }, 0);
140    globalTest!.checkpoint(1);
141}
142
143function testSetTimeoutInvokeCallbackWithSpecifiedParameter(): void {
144    globalTest = new Test(3);
145    let delay = 100;
146    globalTest!.checkpoint(0);
147    let start = Date.now();
148    let para: string = "Parameter"
149    setTimeout((p : string): void => {
150        // To get time Date.now and libuv uses clock_gettime under the hood, but with different parameters. Date.now() uses CLOCK_REALTIME, but libuv uses CLOCK_MONOTONIC.
151        // When we calculate time interval there may be an error. For example time interval measured by Date.now may be 5.9ms round to 5
152        // and time interval measured by libuv is 6.1 round to 6.
153        // To avoid such error just add +1 to time interval.
154        let spentTime = Date.now() - start + 1;
155        if (spentTime < 0) {
156            globalTest!.fail("The callback is called after " + spentTime + "ms. Expected to be called after 0 ms at least.");
157        }
158        if (p !== para) {
159            globalTest!.fail("The parameter passed to the callback is " + p + ". Expected to be " + para + ".");
160        }
161        globalTest!.checkpoint(2);
162    }, delay, para);
163    globalTest!.checkpoint(1);
164}
165
166function testSetTimeoutInvokeCallbackWith4SpecifiedParameters(): void {
167    globalTest = new Test(3);
168    let delay = 100;
169    globalTest!.checkpoint(0);
170    let start = Date.now();
171    let para1: string = "Parameter1";
172    let para2: int = 2;
173    let para3: number = 3.0;
174    let para4: string = "Parameter4";
175
176    setTimeout((p1 :string, p2: int, p3: number, p4: string): void => {
177        // To get time Date.now and libuv uses clock_gettime under the hood, but with different parameters. Date.now() uses CLOCK_REALTIME, but libuv uses CLOCK_MONOTONIC.
178        // When we calculate time interval there may be an error. For example time interval measured by Date.now may be 5.9ms round to 5
179        // and time interval measured by libuv is 6.1 round to 6.
180        // To avoid such error just add +1 to time interval.
181        let spentTime = Date.now() - start + 1;
182        if (spentTime < delay) {
183            globalTest!.fail("The callback is called after " + spentTime + "ms. Expected to be called after " + delay + "ms at least.");
184        }
185        if (p1 !== para1) {
186            globalTest!.fail("The parameter passed to the callback is " + p1 + ". Expected to be " + para1 + ".");
187        }
188        if (p2 !== para2) {
189            globalTest!.fail("The parameter passed to the callback is " + p2 + ". Expected to be " + para2 + ".");
190        }
191        if (p3 !== para3) {
192            globalTest!.fail("The parameter passed to the callback is " + p3 + ". Expected to be " + para3 + ".");
193        }
194        if (p4 !== para4) {
195            globalTest!.fail("The parameter passed to the callback is " + p4 + ". Expected to be " + para4 + ".");
196        }
197        globalTest!.checkpoint(2);
198    }, delay, para1, para2, para3, para4);
199    globalTest!.checkpoint(1);
200}
201
202function testSetIntervalInvokeCallbacWithSpecifiedParameter(): void {
203    globalTest = new Test(6);
204    let sequence = new Array<number>();
205    let delay = 100;
206    let checkpoint = 2;
207    globalTest!.checkpoint(0);
208    let para : string = "para"
209    let start = Date.now();
210    let timerId: number;
211    timerId = setInterval((p: string): void => {
212        // To get time Date.now and libuv uses clock_gettime under the hood, but with different parameters. Date.now() uses CLOCK_REALTIME, but libuv uses CLOCK_MONOTONIC.
213        // When we calculate time interval there may be an error. For example time interval measured by Date.now may be 5.9ms round to 5
214        // and time interval measured by libuv is 6.1 round to 6.
215        // To avoid such error just add +1 to time interval.
216        let spentTime = Date.now() - start + 1;
217        if (spentTime < delay) {
218            globalTest!.fail("The callback is called after " + spentTime + "ms. Expected to be called after " + delay + "ms at least.");
219        }
220        if (p !== para) {
221            globalTest!.fail("The parameter passed to the callback is " + p + ". Expected to be " + para + ".");
222        }
223        if (checkpoint == 5) {
224            clearInterval(timerId);
225        }
226        globalTest!.checkpoint(checkpoint);
227        ++checkpoint;
228    }, delay, para);
229    globalTest!.checkpoint(1);
230}
231
232function testSetIntervalInvokeCallbacWith4SpecifiedParameters(): void {
233    globalTest = new Test(6);
234    let sequence = new Array<number>();
235    let delay = 100;
236    let checkpoint = 2;
237    globalTest!.checkpoint(0);
238    let para1: string = "Parameter1";
239    let para2: int = 2;
240    let para3: number = 3.0;
241    let para4: string = "Parameter4";
242    let start = Date.now();
243    let timerId: number;
244    timerId = setInterval((p1 :string, p2: int, p3: number, p4: string): void => {
245        // To get time Date.now and libuv uses clock_gettime under the hood, but with different parameters. Date.now() uses CLOCK_REALTIME, but libuv uses CLOCK_MONOTONIC.
246        // When we calculate time interval there may be an error. For example time interval measured by Date.now may be 5.9ms round to 5
247        // and time interval measured by libuv is 6.1 round to 6.
248        // To avoid such error just add +1 to time interval.
249        let spentTime = Date.now() - start + 1;
250        if (spentTime < delay) {
251            globalTest!.fail("The callback is called after " + spentTime + "ms. Expected to be called after " + delay + "ms at least.");
252        }
253        if (p1 !== para1) {
254            globalTest!.fail("The parameter passed to the callback is " + p1 + ". Expected to be " + para1 + ".");
255        }
256        if (p2 !== para2) {
257            globalTest!.fail("The parameter passed to the callback is " + p2 + ". Expected to be " + para2 + ".");
258        }
259        if (p3 !== para3) {
260            globalTest!.fail("The parameter passed to the callback is " + p3 + ". Expected to be " + para3 + ".");
261        }
262        if (p4 !== para4) {
263            globalTest!.fail("The parameter passed to the callback is " + p4 + ". Expected to be " + para4 + ".");
264        }
265        if (checkpoint == 5) {
266            clearInterval(timerId);
267        }
268        globalTest!.checkpoint(checkpoint);
269        ++checkpoint;
270    }, delay, para1, para2, para3, para4);
271    globalTest!.checkpoint(1);
272}
273
274function testSetTimeoutWithNegitiveDelay(): void {
275    globalTest = new Test(3);
276    let sequence = new Array<number>();
277    let delay = -10;
278    globalTest!.checkpoint(0);
279    let start = Date.now();
280    setTimeout((): void => {
281        // To get time Date.now and libuv uses clock_gettime under the hood, but with different parameters. Date.now() uses CLOCK_REALTIME, but libuv uses CLOCK_MONOTONIC.
282        // When we calculate time interval there may be an error. For example time interval measured by Date.now may be 5.9ms round to 5
283        // and time interval measured by libuv is 6.1 round to 6.
284        // To avoid such error just add +1 to time interval.
285        let spentTime = Date.now() - start + 1;
286        if (spentTime < 0) {
287            globalTest!.fail("The callback is called after " + spentTime + "ms. Expected to be called after 0 ms at least.");
288        }
289        globalTest!.checkpoint(2);
290    }, delay);
291    globalTest!.checkpoint(1);
292}
293
294function testSetIntervalWithNegitiveDelay(): void {
295    globalTest = new Test(6);
296    let sequence = new Array<number>();
297    let delay = -10;
298    let checkpoint = 2;
299    globalTest!.checkpoint(0);
300    let start = Date.now();
301    let timerId: number;
302    timerId = setInterval((): void => {
303        // To get time Date.now and libuv uses clock_gettime under the hood, but with different parameters. Date.now() uses CLOCK_REALTIME, but libuv uses CLOCK_MONOTONIC.
304        // When we calculate time interval there may be an error. For example time interval measured by Date.now may be 5.9ms round to 5
305        // and time interval measured by libuv is 6.1 round to 6.
306        // To avoid such error just add +1 to time interval.
307        let spentTime = Date.now() - start + 1;
308        if (spentTime < 0) {
309            globalTest!.fail("The callback is called after " + spentTime + "ms. Expected to be called after 0 ms at least.");
310        }
311        if (checkpoint == 5) {
312            clearInterval(timerId);
313        }
314        globalTest!.checkpoint(checkpoint);
315        ++checkpoint;
316    }, delay);
317    globalTest!.checkpoint(1);
318}
319
320function testSetTimeoutWithString(): void {
321    globalTest = new Test(2);
322    let delay = 100;
323    globalTest!.checkpoint(0);
324    setTimeout("test", delay);
325    globalTest!.checkpoint(1);
326}
327
328function testSetIntervalWithString(): void {
329    globalTest = new Test(2);
330    let delay = 100;
331    globalTest!.checkpoint(0);
332    let checkpoint = 2;
333    let id1 = setInterval("test", delay);
334    let id2: number;
335    id2 = setInterval(() => {
336        if (checkpoint == 5) {
337            clearInterval(id1);
338            clearInterval(id2);
339        }
340        checkpoint ++ ;
341    }, delay)
342    globalTest!.checkpoint(1);
343}
344
345function testClearTimerCrossWorker()
346{
347    globalTest = new Test(0);
348    CoroutineExtras.setSchedulingPolicy(CoroutineExtras.POLICY_NON_MAIN);
349    let delay = 100;
350
351    /// Clear worker timer from main worker
352    {
353        let isCleared = new AtomicFlag(false);
354        let workerTimerCb = () => {
355            setTimeout(() => { while (!isCleared.get()) {} }, 0);
356            return setTimeout(() => { assertTrue(false); }, delay);
357        };
358        let id = launch<number, () => number>(workerTimerCb).Await();
359        clearTimeout(id);
360        isCleared.set(true);
361    }
362
363    /// Clear main timer from worker
364    {
365        let triedToClear = false;
366        let id = setTimeout(() => { assertTrue(triedToClear); }, delay);
367        try {
368            launch<void, (id: number) => void>(clearTimeout, id).Await();
369        } catch (e) {
370            assertEQ(e.toString(), "Error: Failed to clear timer. Unable to clear interop timer from non-interop worker");
371            triedToClear = true;
372        }
373        assertTrue(triedToClear);
374    }
375}
376