async-disposable-stack-error-handling.js (3928B)
1 // |jit-test| skip-if: !getBuildConfiguration("explicit-resource-management"); --enable-explicit-resource-management 2 3 load(libdir + "asserts.js"); 4 5 { 6 const disposed = []; 7 const errorToThrow = new Error("error"); 8 const stack = new AsyncDisposableStack(); 9 const obj = { 10 [Symbol.asyncDispose]() { 11 disposed.push(1); 12 throw errorToThrow; 13 }, 14 }; 15 stack.use(obj); 16 assertEq(stack.disposed, false); 17 assertThrowsInstanceOfAsync(async () => { 18 await stack.disposeAsync(); 19 }, Error); 20 assertArrayEq(disposed, [1]); 21 assertEq(stack.disposed, true); 22 } 23 24 { 25 const disposed = []; 26 const errorsToThrow = [new Error("error1"), new Error("error2"), new Error("error3")]; 27 const stack = new AsyncDisposableStack(); 28 for (let i = 0; i < 3; i++) { 29 stack.use({ 30 [Symbol.asyncDispose]() { 31 disposed.push(i); 32 throw errorsToThrow[i]; 33 }, 34 }); 35 } 36 assertEq(stack.disposed, false); 37 assertSuppressionChainAsync(async () => { await stack.disposeAsync() }, errorsToThrow); 38 assertEq(stack.disposed, true); 39 assertArrayEq(disposed, [2, 1, 0]); 40 stack.disposeAsync(); 41 drainJobQueue(); 42 assertArrayEq(disposed, [2, 1, 0]); 43 } 44 45 { 46 const disposed = []; 47 const errorsToThrow = [new Error("error1"), new Error("error2"), new Error("error3"), new Error("error4")]; 48 async function testStackDisposalWithUsingAndErrors() { 49 const stack = new AsyncDisposableStack(); 50 for (let i = 0; i < 3; i++) { 51 stack.use({ 52 [Symbol.asyncDispose]() { 53 disposed.push(i); 54 throw errorsToThrow[i]; 55 }, 56 }); 57 } 58 assertEq(stack.disposed, false); 59 { 60 await using stk = stack; 61 stk.use({ 62 [Symbol.asyncDispose]() { 63 disposed.push(3); 64 throw errorsToThrow[3]; 65 }, 66 }); 67 } 68 } 69 assertSuppressionChainAsync(testStackDisposalWithUsingAndErrors, errorsToThrow); 70 assertArrayEq(disposed, [3, 2, 1, 0]); 71 } 72 73 { 74 const disposed = []; 75 const errorsToThrow = [new Error("error1"), new Error("error2"), new Error("error3")]; 76 async function testStackDisposalWithUseAdoptDeferAndErrors() { 77 const stack = new AsyncDisposableStack(); 78 stack.use({ 79 [Symbol.asyncDispose]() { 80 disposed.push(1); 81 throw errorsToThrow[0]; 82 }, 83 }); 84 stack.adopt(2, (v) => { 85 disposed.push(v); 86 throw errorsToThrow[1]; 87 }); 88 stack.defer(() => { 89 disposed.push(3); 90 throw errorsToThrow[2]; 91 }); 92 assertEq(stack.disposed, false); 93 await stack.disposeAsync(); 94 } 95 assertSuppressionChainAsync(testStackDisposalWithUseAdoptDeferAndErrors, errorsToThrow); 96 assertArrayEq(disposed, [3, 2, 1]); 97 } 98 99 { 100 const disposed = []; 101 const errorsToThrow = [new Error("error1"), new Error("error2"), new Error("error3"), new Error("error4")]; 102 async function testStackDisposalWithUseAdoptDeferAndErrorsAndOutsideError() { 103 await using stack = new AsyncDisposableStack(); 104 stack.use({ 105 [Symbol.asyncDispose]() { 106 disposed.push(1); 107 throw errorsToThrow[0]; 108 }, 109 }); 110 stack.adopt(2, (v) => { 111 disposed.push(v); 112 throw errorsToThrow[1]; 113 }); 114 stack.defer(() => { 115 disposed.push(3); 116 throw errorsToThrow[2]; 117 }); 118 119 throw errorsToThrow[3]; 120 } 121 let caught = false; 122 async function test() { 123 try { 124 await testStackDisposalWithUseAdoptDeferAndErrorsAndOutsideError(); 125 } catch (err) { 126 caught = true; 127 // the error thrown at function end would be suppressed and while 128 // disposing the stack there would be another suppressed error. 129 assertEq(err instanceof SuppressedError, true); 130 assertEq(err.suppressed === errorsToThrow[3], true); 131 assertSuppressionChain(() => { throw err.error }, [errorsToThrow[0], errorsToThrow[1], errorsToThrow[2]]); 132 } finally { 133 assertEq(caught, true); 134 } 135 } 136 test(); 137 drainJobQueue(); 138 assertArrayEq(disposed, [3, 2, 1]); 139 }