1// META: global=window,worker 2'use strict'; 3 4// Tests which patch the global environment are kept separate to avoid 5// interfering with other tests. 6 7const ReadableStream_prototype_locked_get = 8 Object.getOwnPropertyDescriptor(ReadableStream.prototype, 'locked').get; 9 10// Verify that |rs| passes the brand check as a readable stream. 11function isReadableStream(rs) { 12 try { 13 ReadableStream_prototype_locked_get.call(rs); 14 return true; 15 } catch (e) { 16 return false; 17 } 18} 19 20test(t => { 21 const rs = new ReadableStream(); 22 23 const trappedProperties = ['highWaterMark', 'size', 'start', 'type', 'mode']; 24 for (const property of trappedProperties) { 25 // eslint-disable-next-line no-extend-native, accessor-pairs 26 Object.defineProperty(Object.prototype, property, { 27 get() { throw new Error(`${property} getter called`); }, 28 configurable: true 29 }); 30 } 31 t.add_cleanup(() => { 32 for (const property of trappedProperties) { 33 delete Object.prototype[property]; 34 } 35 }); 36 37 const [branch1, branch2] = rs.tee(); 38 assert_true(isReadableStream(branch1), 'branch1 should be a ReadableStream'); 39 assert_true(isReadableStream(branch2), 'branch2 should be a ReadableStream'); 40}, 'ReadableStream tee() should not touch Object.prototype properties'); 41 42test(t => { 43 const rs = new ReadableStream(); 44 45 const oldReadableStream = self.ReadableStream; 46 47 self.ReadableStream = function() { 48 throw new Error('ReadableStream called on global object'); 49 }; 50 51 t.add_cleanup(() => { 52 self.ReadableStream = oldReadableStream; 53 }); 54 55 const [branch1, branch2] = rs.tee(); 56 57 assert_true(isReadableStream(branch1), 'branch1 should be a ReadableStream'); 58 assert_true(isReadableStream(branch2), 'branch2 should be a ReadableStream'); 59}, 'ReadableStream tee() should not call the global ReadableStream'); 60 61promise_test(async t => { 62 const rs = new ReadableStream({ 63 start(c) { 64 c.enqueue(1); 65 c.enqueue(2); 66 c.enqueue(3); 67 c.close(); 68 } 69 }); 70 71 const oldReadableStreamGetReader = ReadableStream.prototype.getReader; 72 73 const ReadableStreamDefaultReader = (new ReadableStream()).getReader().constructor; 74 const oldDefaultReaderRead = ReadableStreamDefaultReader.prototype.read; 75 const oldDefaultReaderCancel = ReadableStreamDefaultReader.prototype.cancel; 76 const oldDefaultReaderReleaseLock = ReadableStreamDefaultReader.prototype.releaseLock; 77 78 self.ReadableStream.prototype.getReader = function() { 79 throw new Error('patched getReader() called'); 80 }; 81 82 ReadableStreamDefaultReader.prototype.read = function() { 83 throw new Error('patched read() called'); 84 }; 85 ReadableStreamDefaultReader.prototype.cancel = function() { 86 throw new Error('patched cancel() called'); 87 }; 88 ReadableStreamDefaultReader.prototype.releaseLock = function() { 89 throw new Error('patched releaseLock() called'); 90 }; 91 92 t.add_cleanup(() => { 93 self.ReadableStream.prototype.getReader = oldReadableStreamGetReader; 94 95 ReadableStreamDefaultReader.prototype.read = oldDefaultReaderRead; 96 ReadableStreamDefaultReader.prototype.cancel = oldDefaultReaderCancel; 97 ReadableStreamDefaultReader.prototype.releaseLock = oldDefaultReaderReleaseLock; 98 }); 99 100 // read the first chunk, then cancel 101 for await (const chunk of rs) { 102 break; 103 } 104 105 // should be able to acquire a new reader 106 const reader = oldReadableStreamGetReader.call(rs); 107 // stream should be cancelled 108 await reader.closed; 109}, 'ReadableStream async iterator should use the original values of getReader() and ReadableStreamDefaultReader ' + 110 'methods'); 111 112test(t => { 113 const oldPromiseThen = Promise.prototype.then; 114 Promise.prototype.then = () => { 115 throw new Error('patched then() called'); 116 }; 117 t.add_cleanup(() => { 118 Promise.prototype.then = oldPromiseThen; 119 }); 120 const [branch1, branch2] = new ReadableStream().tee(); 121 assert_true(isReadableStream(branch1), 'branch1 should be a ReadableStream'); 122 assert_true(isReadableStream(branch2), 'branch2 should be a ReadableStream'); 123}, 'tee() should not call Promise.prototype.then()'); 124 125test(t => { 126 const oldPromiseThen = Promise.prototype.then; 127 Promise.prototype.then = () => { 128 throw new Error('patched then() called'); 129 }; 130 t.add_cleanup(() => { 131 Promise.prototype.then = oldPromiseThen; 132 }); 133 let readableController; 134 const rs = new ReadableStream({ 135 start(c) { 136 readableController = c; 137 } 138 }); 139 const ws = new WritableStream(); 140 rs.pipeTo(ws); 141 readableController.close(); 142}, 'pipeTo() should not call Promise.prototype.then()'); 143