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