1// META: global=window,worker 2// META: script=../resources/test-utils.js 3// META: script=../resources/recording-streams.js 4'use strict'; 5 6// These tests exercise the pathological case of calling WritableStream* methods from within the strategy.size() 7// callback. This is not something any real code should ever do. Failures here indicate subtle deviations from the 8// standard that may affect real, non-pathological code. 9 10const error1 = { name: 'error1' }; 11 12promise_test(() => { 13 let writer; 14 const strategy = { 15 size(chunk) { 16 if (chunk > 0) { 17 writer.write(chunk - 1); 18 } 19 return chunk; 20 } 21 }; 22 23 const ws = recordingWritableStream({}, strategy); 24 writer = ws.getWriter(); 25 return writer.write(2) 26 .then(() => { 27 assert_array_equals(ws.events, ['write', 0, 'write', 1, 'write', 2], 'writes should appear in order'); 28 }); 29}, 'writes should be written in the standard order'); 30 31promise_test(() => { 32 let writer; 33 const events = []; 34 const strategy = { 35 size(chunk) { 36 events.push('size', chunk); 37 if (chunk > 0) { 38 writer.write(chunk - 1) 39 .then(() => events.push('writer.write done', chunk - 1)); 40 } 41 return chunk; 42 } 43 }; 44 const ws = new WritableStream({ 45 write(chunk) { 46 events.push('sink.write', chunk); 47 } 48 }, strategy); 49 writer = ws.getWriter(); 50 return writer.write(2) 51 .then(() => events.push('writer.write done', 2)) 52 .then(() => flushAsyncEvents()) 53 .then(() => { 54 assert_array_equals(events, ['size', 2, 'size', 1, 'size', 0, 55 'sink.write', 0, 'sink.write', 1, 'writer.write done', 0, 56 'sink.write', 2, 'writer.write done', 1, 57 'writer.write done', 2], 58 'events should happen in standard order'); 59 }); 60}, 'writer.write() promises should resolve in the standard order'); 61 62promise_test(t => { 63 let controller; 64 const strategy = { 65 size() { 66 controller.error(error1); 67 return 1; 68 } 69 }; 70 const ws = recordingWritableStream({ 71 start(c) { 72 controller = c; 73 } 74 }, strategy); 75 const resolved = []; 76 const writer = ws.getWriter(); 77 const readyPromise1 = writer.ready.then(() => resolved.push('ready1')); 78 const writePromise = promise_rejects_exactly(t, error1, writer.write(), 79 'write() should reject with the error') 80 .then(() => resolved.push('write')); 81 const readyPromise2 = promise_rejects_exactly(t, error1, writer.ready, 'ready should reject with error1') 82 .then(() => resolved.push('ready2')); 83 const closedPromise = promise_rejects_exactly(t, error1, writer.closed, 'closed should reject with error1') 84 .then(() => resolved.push('closed')); 85 return Promise.all([readyPromise1, writePromise, readyPromise2, closedPromise]) 86 .then(() => { 87 assert_array_equals(resolved, ['ready1', 'write', 'ready2', 'closed'], 88 'promises should resolve in standard order'); 89 assert_array_equals(ws.events, [], 'underlying sink write should not be called'); 90 }); 91}, 'controller.error() should work when called from within strategy.size()'); 92 93promise_test(t => { 94 let writer; 95 const strategy = { 96 size() { 97 writer.close(); 98 return 1; 99 } 100 }; 101 102 const ws = recordingWritableStream({}, strategy); 103 writer = ws.getWriter(); 104 return promise_rejects_js(t, TypeError, writer.write('a'), 'write() promise should reject') 105 .then(() => { 106 assert_array_equals(ws.events, ['close'], 'sink.write() should not be called'); 107 }); 108}, 'close() should work when called from within strategy.size()'); 109 110promise_test(t => { 111 let writer; 112 const strategy = { 113 size() { 114 writer.abort(error1); 115 return 1; 116 } 117 }; 118 119 const ws = recordingWritableStream({}, strategy); 120 writer = ws.getWriter(); 121 return promise_rejects_exactly(t, error1, writer.write('a'), 'write() promise should reject') 122 .then(() => { 123 assert_array_equals(ws.events, ['abort', error1], 'sink.write() should not be called'); 124 }); 125}, 'abort() should work when called from within strategy.size()'); 126 127promise_test(t => { 128 let writer; 129 const strategy = { 130 size() { 131 writer.releaseLock(); 132 return 1; 133 } 134 }; 135 136 const ws = recordingWritableStream({}, strategy); 137 writer = ws.getWriter(); 138 const writePromise = promise_rejects_js(t, TypeError, writer.write('a'), 'write() promise should reject'); 139 const readyPromise = promise_rejects_js(t, TypeError, writer.ready, 'ready promise should reject'); 140 const closedPromise = promise_rejects_js(t, TypeError, writer.closed, 'closed promise should reject'); 141 return Promise.all([writePromise, readyPromise, closedPromise]) 142 .then(() => { 143 assert_array_equals(ws.events, [], 'sink.write() should not be called'); 144 }); 145}, 'releaseLock() should abort the write() when called within strategy.size()'); 146 147promise_test(t => { 148 let writer1; 149 let ws; 150 let writePromise2; 151 let closePromise; 152 let closedPromise2; 153 const strategy = { 154 size(chunk) { 155 if (chunk > 0) { 156 writer1.releaseLock(); 157 const writer2 = ws.getWriter(); 158 writePromise2 = writer2.write(0); 159 closePromise = writer2.close(); 160 closedPromise2 = writer2.closed; 161 } 162 return 1; 163 } 164 }; 165 ws = recordingWritableStream({}, strategy); 166 writer1 = ws.getWriter(); 167 const writePromise1 = promise_rejects_js(t, TypeError, writer1.write(1), 'write() promise should reject'); 168 const readyPromise = promise_rejects_js(t, TypeError, writer1.ready, 'ready promise should reject'); 169 const closedPromise1 = promise_rejects_js(t, TypeError, writer1.closed, 'closed promise should reject'); 170 return Promise.all([writePromise1, readyPromise, closedPromise1, writePromise2, closePromise, closedPromise2]) 171 .then(() => { 172 assert_array_equals(ws.events, ['write', 0, 'close'], 'sink.write() should only be called once'); 173 }); 174}, 'original reader should error when new reader is created within strategy.size()'); 175