|
| 1 | +"use strict"; |
| 2 | +// Flags: --expose-gc |
| 3 | + |
| 4 | +const theError = new Error("Some error"); |
| 5 | + |
| 6 | +// The test module throws an error during Init, but in order for its exports to |
| 7 | +// not be lost, it attaches them to the error's "bindings" property. This way, |
| 8 | +// we can make sure that exceptions thrown during the module initialization |
| 9 | +// phase are propagated through require() into JavaScript. |
| 10 | +// https://github.com/nodejs/node/issues/19437 |
| 11 | +const test_exception = (function () { |
| 12 | + let resultingException; |
| 13 | + try { |
| 14 | + loadAddon("test_exception"); |
| 15 | + } catch (anException) { |
| 16 | + resultingException = anException; |
| 17 | + } |
| 18 | + assert.strictEqual(resultingException.message, "Error during Init"); |
| 19 | + return resultingException.binding; |
| 20 | +})(); |
| 21 | + |
| 22 | +{ |
| 23 | + const throwTheError = () => { |
| 24 | + throw theError; |
| 25 | + }; |
| 26 | + |
| 27 | + // Test that the native side successfully captures the exception |
| 28 | + let returnedError = test_exception.returnException(throwTheError); |
| 29 | + assert.strictEqual(returnedError, theError); |
| 30 | + |
| 31 | + // Test that the native side passes the exception through |
| 32 | + assert.throws( |
| 33 | + () => { |
| 34 | + test_exception.allowException(throwTheError); |
| 35 | + }, |
| 36 | + (err) => err === theError, |
| 37 | + ); |
| 38 | + |
| 39 | + // Test that the exception thrown above was marked as pending |
| 40 | + // before it was handled on the JS side |
| 41 | + const exception_pending = test_exception.wasPending(); |
| 42 | + assert.strictEqual( |
| 43 | + exception_pending, |
| 44 | + true, |
| 45 | + "Exception not pending as expected," + |
| 46 | + ` .wasPending() returned ${exception_pending}`, |
| 47 | + ); |
| 48 | + |
| 49 | + // Test that the native side does not capture a non-existing exception |
| 50 | + returnedError = test_exception.returnException(mustCall()); |
| 51 | + assert.strictEqual( |
| 52 | + returnedError, |
| 53 | + undefined, |
| 54 | + "Returned error should be undefined when no exception is" + |
| 55 | + ` thrown, but ${returnedError} was passed`, |
| 56 | + ); |
| 57 | +} |
| 58 | + |
| 59 | +{ |
| 60 | + const throwTheError = class { |
| 61 | + constructor() { |
| 62 | + throw theError; |
| 63 | + } |
| 64 | + }; |
| 65 | + |
| 66 | + // Test that the native side successfully captures the exception |
| 67 | + let returnedError = test_exception.constructReturnException(throwTheError); |
| 68 | + assert.strictEqual(returnedError, theError); |
| 69 | + |
| 70 | + // Test that the native side passes the exception through |
| 71 | + assert.throws( |
| 72 | + () => { |
| 73 | + test_exception.constructAllowException(throwTheError); |
| 74 | + }, |
| 75 | + (err) => err === theError, |
| 76 | + ); |
| 77 | + |
| 78 | + // Test that the exception thrown above was marked as pending |
| 79 | + // before it was handled on the JS side |
| 80 | + const exception_pending = test_exception.wasPending(); |
| 81 | + assert.strictEqual( |
| 82 | + exception_pending, |
| 83 | + true, |
| 84 | + "Exception not pending as expected," + |
| 85 | + ` .wasPending() returned ${exception_pending}`, |
| 86 | + ); |
| 87 | + |
| 88 | + // Test that the native side does not capture a non-existing exception |
| 89 | + returnedError = test_exception.constructReturnException(mustCall()); |
| 90 | + assert.strictEqual( |
| 91 | + returnedError, |
| 92 | + undefined, |
| 93 | + "Returned error should be undefined when no exception is" + |
| 94 | + ` thrown, but ${returnedError} was passed`, |
| 95 | + ); |
| 96 | +} |
| 97 | + |
| 98 | +{ |
| 99 | + // Test that no exception appears that was not thrown by us |
| 100 | + let caughtError; |
| 101 | + try { |
| 102 | + test_exception.allowException(mustCall()); |
| 103 | + } catch (anError) { |
| 104 | + caughtError = anError; |
| 105 | + } |
| 106 | + assert.strictEqual( |
| 107 | + caughtError, |
| 108 | + undefined, |
| 109 | + "No exception originated on the native side, but" + |
| 110 | + ` ${caughtError} was passed`, |
| 111 | + ); |
| 112 | + |
| 113 | + // Test that the exception state remains clear when no exception is thrown |
| 114 | + const exception_pending = test_exception.wasPending(); |
| 115 | + assert.strictEqual( |
| 116 | + exception_pending, |
| 117 | + false, |
| 118 | + "Exception state did not remain clear as expected," + |
| 119 | + ` .wasPending() returned ${exception_pending}`, |
| 120 | + ); |
| 121 | +} |
| 122 | + |
| 123 | +{ |
| 124 | + // Test that no exception appears that was not thrown by us |
| 125 | + let caughtError; |
| 126 | + try { |
| 127 | + test_exception.constructAllowException(mustCall()); |
| 128 | + } catch (anError) { |
| 129 | + caughtError = anError; |
| 130 | + } |
| 131 | + assert.strictEqual( |
| 132 | + caughtError, |
| 133 | + undefined, |
| 134 | + "No exception originated on the native side, but" + |
| 135 | + ` ${caughtError} was passed`, |
| 136 | + ); |
| 137 | + |
| 138 | + // Test that the exception state remains clear when no exception is thrown |
| 139 | + const exception_pending = test_exception.wasPending(); |
| 140 | + assert.strictEqual( |
| 141 | + exception_pending, |
| 142 | + false, |
| 143 | + "Exception state did not remain clear as expected," + |
| 144 | + ` .wasPending() returned ${exception_pending}`, |
| 145 | + ); |
| 146 | +} |
0 commit comments