1/** 2 * Copyright (c) 2021-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 16class Test { 17 private static UNSET: int = 0; 18 private static SUCCESS: int = 1; 19 20 constructor(iterations: int = 0) { 21 this.result = Test.UNSET; 22 this.iterations = iterations; 23 } 24 25 success(): void { 26 if (this.result == Test.UNSET) { 27 this.result = Test.SUCCESS; 28 } 29 } 30 31 fail(): void { 32 console.println("Test failed"); 33 throw new Error(); 34 } 35 36 check(): void { 37 if (this.result == Test.SUCCESS) { 38 return; 39 } 40 if (this.result == Test.UNSET) { 41 console.println("Test result is not set"); 42 } 43 throw new Error(); 44 } 45 46 ready(): boolean { 47 if (this.iterations == 0) { 48 return true; 49 } 50 this.iterations--; 51 return false; 52 } 53 54 static FATAL: int = 0; 55 static ERROR: int = 1; 56 static INFO: int = 2; 57 // private log_level: int = 5; 58 private log_level: int = 1; 59 60 setLogLevel(lvl: int): void { 61 this.log_level = lvl; 62 } 63 64 msg(s: String, lvl: int): void { 65 if (lvl <= this.log_level) { 66 console.println(s); 67 } 68 } 69 70 private result: int; 71 private iterations: int; 72} 73let globalTest: Test | null = null; 74 75function check(): int { 76 globalTest!.check(); 77 return 0; 78} 79 80function ready(): boolean { 81 return globalTest!.ready(); 82} 83 84function testPendingPromise(): int { 85 globalTest = new Test(); 86 let p = new Promise<Object>((resolve: (value: Object) => void): void => { 87 globalTest!.success() 88 }); 89 globalTest!.check(); 90 p.then<void>((): void => { 91 globalTest!.fail(); 92 }); 93 p.catch<void>((error: NullishType): void => { 94 globalTest!.fail(); 95 }); 96 // Check callback are not called inside 'then' and 'catch' 97 globalTest!.check(); 98 return 0; 99} 100 101function testResolvedPromise(): int { 102 let obj = new Object(); 103 let p = new Promise<Object>((resolve: (value: Object) => void): void => { 104 resolve(obj); 105 }); 106 globalTest = new Test(); 107 p.then<Object | null>((value: Object): Object | null => { 108 if (value == obj) { 109 globalTest!.success(); 110 } else { 111 globalTest!.fail(); 112 } 113 return null; 114 }); 115 p.catch<Object | null>((err: NullishType): Object | null => { 116 globalTest!.fail(); 117 return null; 118 }); 119 return 0; 120} 121 122function testRejectedPromise(): int { 123 globalTest = new Test(); 124 let error = new Error(); 125 try { 126 let p = new Promise<Object>((resolve: (value: Object) => void): void => { 127 throw error; 128 }); 129 p.then<Object | null>((value: Object): Object | null => { 130 globalTest!.fail(); 131 return null; 132 }); 133 p.catch<Object | null>((err: NullishType): Object => { 134 if (err == error) { 135 globalTest!.success(); 136 } else { 137 globalTest!.fail(); 138 } 139 }); 140 } catch (e: Exception) { 141 globalTest!.fail(); 142 } 143 return 0; 144} 145 146class ThenBeforeResolveFixture { 147 public fn: (value: Object) => void = (value: Object) => {}; 148 public state = 0; 149} 150 151function testThenBeforeResolve(): int { 152 globalTest = new Test(); 153 let fixture = new ThenBeforeResolveFixture(); 154 let p = new Promise<Object>((resolve: (value: Object) => void): void => { 155 fixture.fn = resolve; 156 }); 157 let obj = new Object(); 158 p.then<Object | null>((value: Object): Object | null => { 159 if (value == obj) { 160 if (fixture.state == 0) { 161 fixture.state = 1; 162 } else { 163 console.println("Wrong 'then' call order"); 164 globalTest!.fail(); 165 } 166 } else { 167 console.println("Then is called with wrong object"); 168 globalTest!.fail(); 169 } 170 return null; 171 }); 172 p.then<Object | null>((value: Object): Object | null => { 173 if (value == obj) { 174 if (fixture.state == 1) { 175 globalTest!.success(); 176 } else { 177 console.println("Wrong 'then' call order"); 178 globalTest!.fail(); 179 } 180 } else { 181 console.println("Then is called with wrong object"); 182 globalTest!.fail(); 183 } 184 return null; 185 }); 186 fixture.fn(obj); 187 return 0; 188} 189 190function testPromiseEmptyThen(): int { 191 globalTest = new Test(); 192 let p = new Promise<Object>((resolve: (value: Object) => void): void => { 193 resolve(new Object()); 194 }); 195 let nextP = p.then<Object>((): Object => { 196 globalTest!.success(); 197 }); 198 return 0; 199} 200 201class PromiseChainFixture { 202 public state = 0; 203} 204 205function testPromiseChain(): int { 206 globalTest = new Test(2); 207 let fixture = new PromiseChainFixture(); 208 let p = new Promise<Object>((resolve: (value: Object) => void): void => { 209 resolve(new Object()); 210 }); 211 // NOTE(audovichenko): Remove p1 and p2 variables #17359 212 let p1: Promise<void> = p.then<void>((): void => { 213 if (fixture.state == 0) { 214 fixture.state = 1; 215 } else { 216 globalTest!.fail(); 217 } 218 }); 219 let p2: Promise<void> = p1.then<void>((): void => { 220 if (fixture.state == 1) { 221 fixture.state = 2; 222 } else { 223 globalTest!.fail(); 224 } 225 }); 226 p2.then<void>((): void => { 227 if (fixture.state == 2) { 228 globalTest!.success(); 229 } else { 230 globalTest!.fail(); 231 } 232 }); 233 return 0; 234} 235 236function testPromiseCatchFinallyChain(): int { 237 globalTest = new Test(2); 238 let fixture = new PromiseChainFixture(); 239 let p: Promise<Object> = Promise.reject<Object>(new Object()); 240 // NOTE(audovichenko): Remove p1 and p2 variables #17359 241 let p1: Promise<void> = p.then<void>((v: Object): void => { 242 globalTest!.fail(); 243 }); 244 let p2: Promise<void> = p1.catch<void>((value: NullishType): void => { 245 if (fixture.state == 0) { 246 fixture.state = 1; 247 } else { 248 globalTest!.fail(); 249 } 250 }); 251 p2.finally((): void => { 252 if (fixture.state == 1) { 253 globalTest!.success(); 254 } else { 255 globalTest!.fail(); 256 } 257 }); 258 return 0; 259} 260 261function testResolvePromiseThenFinally(): int { 262 globalTest = new Test(1); 263 let fixture = new PromiseChainFixture(); 264 let p = Promise.resolve<Object>(new Object()); 265 // NOTE(audovichenko): Remove p1 and p2 variables #17359 266 let p1: Promise<void> = p.then<void, void>((value: Object): void => { 267 if (fixture.state == 0) { 268 fixture.state = 1; 269 } else { 270 globalTest!.fail(); 271 } 272 }, (error: NullishType): void => { 273 globalTest!.fail(); 274 }); 275 p1.finally((): void => { 276 if (fixture.state == 1) { 277 globalTest!.success(); 278 } else { 279 globalTest!.fail(); 280 } 281 }); 282 return 0; 283} 284 285function testRejectPromiseThenFinally(): int { 286 globalTest = new Test(1); 287 let fixture = new PromiseChainFixture(); 288 let p = Promise.reject<Object>(new Object()); 289 // NOTE(audovichenko): Remove p1 and p2 variables #17359 290 let p1: Promise<void> = p.then<void, void>((value: Object): void => { 291 globalTest!.fail(); 292 }, (error: NullishType): void => { 293 if (fixture.state == 0) { 294 fixture.state = 1; 295 } else { 296 globalTest!.fail(); 297 } 298 }); 299 p1.finally((): void => { 300 if (fixture.state == 1) { 301 globalTest!.success(); 302 } else { 303 globalTest!.fail(); 304 } 305 }); 306 return 0; 307} 308 309function testReturnPromise(): Promise<Object> { 310 return new Promise<Object>((resolve: (value: Object) => void): void => { 311 resolve("Panda"); 312 }); 313} 314 315async function testReturnPromiseFromAsync(): Promise<Object> { 316 return new Promise<Object>((resolve: (value: Object) => void): void => { 317 resolve("Panda"); 318 }); 319} 320 321let resolvePromiseFn: ((value: Object) => void) | null = null; 322 323function testReturnPendingPromise(): Promise<Object> { 324 return new Promise<Object>((resolve: (value: Object) => void): void => { 325 resolvePromiseFn = resolve; 326 }); 327} 328 329function resolvePendingPromise(): boolean { 330 if (resolvePromiseFn == null) { 331 return false; 332 } 333 (resolvePromiseFn as (value: Object) => void)("Panda"); 334 return true; 335} 336 337let unresolved1: Object | null = null; 338let unresolved2: Object | null = null; 339 340async function asyncFuncAwait(): Promise<Object | null> { 341 let promise: Promise<Object> = new Promise<Object>((resolve: (obj: Object) => void): void => { 342 resolve("resolved"); 343 }); 344 unresolved1 = await promise; 345 return null; 346} 347 348let asyncLambdaAwait: () => Promise<Object | null> = async (): Promise<Object | null> => { 349 let promise: Promise<Object> = new Promise<Object>((resolve: (obj: Object) => void): void => { 350 resolve("resolved"); 351 }); 352 unresolved2 = await promise; 353 return null; 354} 355 356function testAwaitPromise(): int { 357 globalTest = new Test(); 358 let p1: Promise<Object | null> = asyncFuncAwait(); 359 let p2: Promise<Object | null> = asyncLambdaAwait(); 360 if (unresolved1 != "resolved" || unresolved2 != "resolved") { 361 globalTest!.fail(); 362 } 363 globalTest!.success(); 364 return 0; 365} 366 367function makeResolvedPromise(v: String): Promise<Object> { 368 return new Promise<Object>((resolve: (value: Object) => void): void => { 369 resolve(v); 370 }); 371} 372 373async function testAwaitJsPromise(pendingP: Promise<Object>): Promise<Object> { 374 globalTest = new Test(); 375 376 globalTest!.msg("testAwaitJsPromise: start", Test.INFO); 377 let res: String = (await pendingP) as String; 378 379 globalTest!.msg("testAwaitJsPromise: await result is: " + res, Test.INFO); 380 381 if (res != "JS_PROMISE_RESULT") { 382 globalTest!.msg("testAwaitJsPromise: await result is wrong!", Test.FATAL); 383 globalTest!.fail(); 384 } else { 385 globalTest!.msg("testAwaitJsPromise: await result is CORRECT!", Test.INFO); 386 globalTest!.success(); 387 } 388 389 globalTest!.msg("testAwaitJsPromise: done", Test.INFO); 390 /** 391 * NOTE(konstanting, #I67QXC): add a test where we would return here a PENDING promise. 392 * Currently this leads to a crash, because: 393 * - testAwaitJsPromise$asyncImpl resolves its linked promise (P1) with makeResolvedPromise's result (P2) 394 * - since we returned P1 to JS as PENDING (due to await presence), it has listeners 395 * - thus, P1 resolution triggers PandaEtsVM::FirePromiseStateChanged, which acquires promise_listeners_lock_ 396 * - this leads to wrapping P1's resolution value (P2) into a JS promise 397 * - and since P2 is still PENDING, we must add a listener to it in order to notify JS of its resolution later on 398 * - this triggers PandaEtsVM::AddPromiseListener, which acquires already acquired promise_listeners_lock_ within 399 * the same thread 400 * - BOOM! Assertion fires. 401 */ 402 return makeResolvedPromise("Panda"); 403} 404 405async function testAsyncBoolean(): Promise<boolean> { 406 return true; 407} 408 409async function testAsyncByte(): Promise<byte> { 410 let x: byte = 127; 411 return x; 412} 413 414async function testAsyncChar(): Promise<char> { 415 return c'x'; 416} 417 418async function testAsyncShort(): Promise<short> { 419 let x: short = 32767; 420 return x; 421} 422 423async function testAsyncInt(): Promise<int> { 424 return 5; 425} 426 427async function testAsyncLong(): Promise<long> { 428 return Long.MAX_VALUE; 429} 430 431async function testAsyncFloat(): Promise<float> { 432 let x: float = 3.14; 433 return x; 434} 435 436async function testAsyncDouble(): Promise<double> { 437 return 3.2; 438} 439 440async function testAsyncString(): Promise<String> { 441 return "Panda"; 442} 443 444async function testAsyncVoid(): Promise<void> { return undefined } 445async function testAsyncVoidEmpty(): Promise<void> {} 446async function testAsyncVoidNothing() {} 447 448function testPromiseAllEmpty(): void { 449 globalTest = new Test(); 450 let promises: Promise<Object>[] = []; 451 Promise.all(promises).then<void>((values: Array<Object>): void => { 452 if (values == null || values.length != 0) { 453 globalTest!.fail(); 454 } else { 455 globalTest!.success(); 456 } 457 }); 458} 459 460function testPromiseAllResolved(): void { 461 globalTest = new Test(1); 462 let p1: Promise<Object> = Promise.resolve<Object>("abc"); 463 let p2: Promise<Object> = Promise.resolve<Object>("def"); 464 let p3: Promise<Object> = Promise.resolve<Object>("xyz"); 465 466 Promise.all<Object>([ 467 p1, p2, p3 468 ]).then<void>((values: Array<Object>): void => { 469 if (values.length != 3) { 470 globalTest!.fail(); 471 } 472 if (values[0] != "abc") { 473 globalTest!.fail(); 474 } 475 if (values[1] != "def") { 476 globalTest!.fail(); 477 } 478 if (values[2] != "xyz") { 479 globalTest!.fail(); 480 } 481 globalTest!.success(); 482 }); 483} 484 485function testPromiseAllRejected(): void { 486 globalTest = new Test(1); 487 let p1: Promise<Object> = Promise.resolve<Object>("abc"); 488 let p2: Promise<Object> = Promise.reject<Object>("def"); 489 let p3: Promise<Object> = Promise.resolve<Object>("xyz"); 490 Promise.all([ 491 p1, p2, p3 492 ]).then<void, void>((v: Object): void => { 493 globalTest!.fail(); 494 }, (err: NullishType): void => { 495 if (err != "def") { 496 globalTest!.fail(); 497 } else { 498 globalTest!.success(); 499 } 500 }); 501} 502 503function testPromiseAllRawValues(): void { 504 globalTest = new Test(1); 505 let p1: Object = "abc"; 506 let p2: Object = "def"; 507 let p3: Object = "xyz"; 508 509 Promise.all<Object>([ 510 p1, p2, p3 511 ]).then<void>((values: Array<Object>): void => { 512 if (values.length != 3) { 513 globalTest!.fail(); 514 } 515 if (values[0] != "abc") { 516 globalTest!.fail(); 517 } 518 if (values[1] != "def") { 519 globalTest!.fail(); 520 } 521 if (values[2] != "xyz") { 522 globalTest!.fail(); 523 } 524 globalTest!.success(); 525 }); 526} 527 528function testPromiseAllIterable(): void { 529 globalTest = new Test(1); 530 let array = new Array<Object|PromiseLike<Object>>(); 531 array.push(Promise.resolve<Object>("abc")); 532 array.push("def"); 533 array.push(Promise.resolve<Object>("xyz")); 534 535 Promise.all<Object>(array).then<void>((values: Array<Object>): void => { 536 if (values.length != 3) { 537 globalTest!.fail(); 538 } 539 if (values[0] != "abc") { 540 globalTest!.fail(); 541 } 542 if (values[1] != "def") { 543 globalTest!.fail(); 544 } 545 if (values[2] != "xyz") { 546 globalTest!.fail(); 547 } 548 globalTest!.success(); 549 }); 550} 551 552function testPromiseAllSettledEmpty(): void { 553 globalTest = new Test(); 554 let promises: Promise<Object>[] = []; 555 Promise.allSettled<Object>(promises).then<void, void>((values: PromiseSettledResult<Object>[]): void => { 556 if (values.length != 0) { 557 globalTest!.fail(); 558 } 559 globalTest!.success(); 560 }, (err: NullishType): void => { 561 globalTest!.fail(); 562 }); 563} 564 565function testPromiseAllSettled(): void { 566 globalTest = new Test(1); 567 let p1: Promise<Object> = Promise.resolve<Object>("abc"); 568 let p2: Promise<Object> = Promise.reject<Object>("def"); 569 let p3: Promise<Object> = Promise.resolve<Object>("xyz"); 570 Promise.allSettled([ 571 p1, p2, p3 572 ]).then<void, void>((result: PromiseSettledResult<Object>[]): void => { 573 if (result.length != 3) { 574 globalTest!.fail(); 575 } 576 if (!(result[0] instanceof PromiseFulfilledResult)) { 577 globalTest!.fail(); 578 } 579 let res0 = result[0] as PromiseFulfilledResult<Object>; 580 if (res0.status != "fulfilled" || res0.value != "abc") { 581 globalTest!.fail(); 582 } 583 if (!(result[1] instanceof PromiseRejectedResult)) { 584 globalTest!.fail(); 585 } 586 let res1 = result[1] as PromiseRejectedResult; 587 if (res1.status != "rejected" || res1.reason != "def") { 588 globalTest!.fail(); 589 } 590 if (!(result[2] instanceof PromiseFulfilledResult)) { 591 globalTest!.fail(); 592 } 593 let res2 = result[2] as PromiseFulfilledResult<Object>; 594 if (res2.status != "fulfilled" || res2.value != "xyz") { 595 globalTest!.fail(); 596 } 597 globalTest!.success(); 598 }, (err: NullishType): void => { 599 globalTest!.fail(); 600 }); 601} 602 603function testPromiseAnyEmpty(): void { 604 globalTest = new Test(); 605 let promises: Promise<Object>[] = []; 606 Promise.any(promises).then<void, void>((v: Object): void => { 607 globalTest!.fail(); 608 }, (err: NullishType): void => { 609 if (err != null && err instanceof AggregateError) { 610 globalTest!.success(); 611 } else { 612 globalTest!.fail(); 613 } 614 }); 615} 616 617function testPromiseAnyResolved(): void { 618 globalTest = new Test(1); 619 let p1: Promise<Object> = Promise.reject<Object>("abc"); 620 let p2: Promise<Object> = Promise.reject<Object>("def"); 621 let p3: Promise<Object> = Promise.resolve<Object>("xyz"); 622 Promise.any([ 623 p1, p2, p3 624 ]).then<void>((value: Object): void => { 625 if (value != "xyz") { 626 globalTest!.fail(); 627 } 628 globalTest!.success(); 629 }); 630} 631 632function testPromiseAnyRejected(): void { 633 globalTest = new Test(1); 634 let p1: Promise<Object> = Promise.reject<Object>("abc"); 635 let p2: Promise<Object> = Promise.reject<Object>("def"); 636 let p3: Promise<Object> = Promise.reject<Object>("xyz"); 637 Promise.any([ 638 p1, p2, p3 639 ]).then<void, void>((v: Object): void => { 640 globalTest!.fail(); 641 }, (err: NullishType): void => { 642 if (err == null || !(err instanceof AggregateError)) { 643 globalTest!.fail(); 644 } else { 645 globalTest!.success(); 646 } 647 }); 648} 649 650function testPromiseAnyRawValues(): void { 651 globalTest = new Test(1); 652 Promise.any([ 653 "abc", "def", "xyz" 654 ]).then<void>((value: Object): void => { 655 if (value != "abc") { 656 globalTest!.fail(); 657 } 658 globalTest!.success(); 659 }); 660} 661 662function testPromiseAnyIterable(): void { 663 globalTest = new Test(); 664 let array = new Array<Object|PromiseLike<Object>>(); 665 array.push(Promise.reject<Object>("def")); 666 array.push(Promise.resolve<Object>("xyz")); 667 Promise.any<Object>(array).then<void>((value: Object): void => { 668 if (value != "xyz") { 669 globalTest!.fail(); 670 } 671 globalTest!.success(); 672 }); 673} 674 675function testPromiseRaceResolved(): void { 676 globalTest = new Test(1); 677 let p1: Promise<Object> = Promise.resolve<Object>("abc"); 678 let p2: Promise<Object> = Promise.reject<Object>("def"); 679 Promise.race([ 680 p1, p2 681 ]).then<void, void>((value: Object): void => { 682 if (value != "abc") { 683 globalTest!.fail(); 684 } 685 globalTest!.success(); 686 }, (error: NullishType): void => { 687 globalTest!.fail(); 688 }); 689} 690 691function testPromiseRaceRejected(): void { 692 globalTest = new Test(1); 693 let p1: Promise<Object> = Promise.reject<Object>("abc"); 694 let p2: Promise<Object> = Promise.resolve<Object>("def"); 695 Promise.race([ 696 p1, p2 697 ]).then<void, void>((value: Object): void => { 698 globalTest!.fail(); 699 }, (error: NullishType): void => { 700 if (error != "abc") { 701 globalTest!.fail(); 702 } 703 globalTest!.success(); 704 }); 705} 706 707let promiseFixture: Promise<void>|null = null; 708 709function getPromise(): Promise<void> { 710 promiseFixture = Promise.resolve(); 711 return promiseFixture!; 712} 713 714function setAndCheckPromise(p: Promise<void>): void { 715 globalTest = new Test(); 716 if (promiseFixture == null) { 717 console.log("Promise is not set"); 718 globalTest!.fail(); 719 } 720 if (promiseFixture !== p) { 721 console.log("Expected the returned promise and the argument are the same but they differs"); 722 globalTest!.fail(); 723 } 724} 725 726function getTheSamePromise(p: Promise<void>): Promise<void> { 727 return p; 728} 729