1// META: global=window,worker 2// META: script=../resources/recording-streams.js 3// META: script=../resources/test-utils.js 4'use strict'; 5 6// Here we just test that the strategies are correctly passed to the readable and writable sides. We assume that 7// ReadableStream and WritableStream will correctly apply the strategies when they are being used by a TransformStream 8// and so it isn't necessary to repeat their tests here. 9 10test(() => { 11 const ts = new TransformStream({}, { highWaterMark: 17 }); 12 assert_equals(ts.writable.getWriter().desiredSize, 17, 'desiredSize should be 17'); 13}, 'writableStrategy highWaterMark should work'); 14 15promise_test(() => { 16 const ts = recordingTransformStream({}, undefined, { highWaterMark: 9 }); 17 const writer = ts.writable.getWriter(); 18 for (let i = 0; i < 10; ++i) { 19 writer.write(i); 20 } 21 return delay(0).then(() => { 22 assert_array_equals(ts.events, [ 23 'transform', 0, 'transform', 1, 'transform', 2, 'transform', 3, 'transform', 4, 24 'transform', 5, 'transform', 6, 'transform', 7, 'transform', 8], 25 'transform() should have been called 9 times'); 26 }); 27}, 'readableStrategy highWaterMark should work'); 28 29promise_test(t => { 30 let writableSizeCalled = false; 31 let readableSizeCalled = false; 32 let transformCalled = false; 33 const ts = new TransformStream( 34 { 35 transform(chunk, controller) { 36 t.step(() => { 37 transformCalled = true; 38 assert_true(writableSizeCalled, 'writableStrategy.size() should have been called'); 39 assert_false(readableSizeCalled, 'readableStrategy.size() should not have been called'); 40 controller.enqueue(chunk); 41 assert_true(readableSizeCalled, 'readableStrategy.size() should have been called'); 42 }); 43 } 44 }, 45 { 46 size() { 47 writableSizeCalled = true; 48 return 1; 49 } 50 }, 51 { 52 size() { 53 readableSizeCalled = true; 54 return 1; 55 }, 56 highWaterMark: Infinity 57 }); 58 return ts.writable.getWriter().write().then(() => { 59 assert_true(transformCalled, 'transform() should be called'); 60 }); 61}, 'writable should have the correct size() function'); 62 63test(() => { 64 const ts = new TransformStream(); 65 const writer = ts.writable.getWriter(); 66 assert_equals(writer.desiredSize, 1, 'default writable HWM is 1'); 67 writer.write(undefined); 68 assert_equals(writer.desiredSize, 0, 'default chunk size is 1'); 69}, 'default writable strategy should be equivalent to { highWaterMark: 1 }'); 70 71promise_test(t => { 72 const ts = new TransformStream({ 73 transform(chunk, controller) { 74 return t.step(() => { 75 assert_equals(controller.desiredSize, 0, 'desiredSize should be 0'); 76 controller.enqueue(undefined); 77 // The first chunk enqueued is consumed by the pending read(). 78 assert_equals(controller.desiredSize, 0, 'desiredSize should still be 0'); 79 controller.enqueue(undefined); 80 assert_equals(controller.desiredSize, -1, 'desiredSize should be -1'); 81 }); 82 } 83 }); 84 const writePromise = ts.writable.getWriter().write(); 85 return ts.readable.getReader().read().then(() => writePromise); 86}, 'default readable strategy should be equivalent to { highWaterMark: 0 }'); 87 88test(() => { 89 assert_throws_js(RangeError, () => new TransformStream(undefined, { highWaterMark: -1 }), 90 'should throw RangeError for negative writableHighWaterMark'); 91 assert_throws_js(RangeError, () => new TransformStream(undefined, undefined, { highWaterMark: -1 }), 92 'should throw RangeError for negative readableHighWaterMark'); 93 assert_throws_js(RangeError, () => new TransformStream(undefined, { highWaterMark: NaN }), 94 'should throw RangeError for NaN writableHighWaterMark'); 95 assert_throws_js(RangeError, () => new TransformStream(undefined, undefined, { highWaterMark: NaN }), 96 'should throw RangeError for NaN readableHighWaterMark'); 97}, 'a RangeError should be thrown for an invalid highWaterMark'); 98 99const objectThatConvertsTo42 = { 100 toString() { 101 return '42'; 102 } 103}; 104 105test(() => { 106 const ts = new TransformStream(undefined, { highWaterMark: objectThatConvertsTo42 }); 107 const writer = ts.writable.getWriter(); 108 assert_equals(writer.desiredSize, 42, 'writable HWM is 42'); 109}, 'writableStrategy highWaterMark should be converted to a number'); 110 111test(() => { 112 const ts = new TransformStream({ 113 start(controller) { 114 assert_equals(controller.desiredSize, 42, 'desiredSize should be 42'); 115 } 116 }, undefined, { highWaterMark: objectThatConvertsTo42 }); 117}, 'readableStrategy highWaterMark should be converted to a number'); 118 119promise_test(t => { 120 const ts = new TransformStream(undefined, undefined, { 121 size() { return NaN; }, 122 highWaterMark: 1 123 }); 124 const writer = ts.writable.getWriter(); 125 return promise_rejects_js(t, RangeError, writer.write(), 'write should reject'); 126}, 'a bad readableStrategy size function should cause writer.write() to reject on an identity transform'); 127 128promise_test(t => { 129 const ts = new TransformStream({ 130 transform(chunk, controller) { 131 // This assert has the important side-effect of catching the error, so transform() does not throw. 132 assert_throws_js(RangeError, () => controller.enqueue(chunk), 'enqueue should throw'); 133 } 134 }, undefined, { 135 size() { 136 return -1; 137 }, 138 highWaterMark: 1 139 }); 140 141 const writer = ts.writable.getWriter(); 142 return writer.write().then(() => { 143 return Promise.all([ 144 promise_rejects_js(t, RangeError, writer.ready, 'ready should reject'), 145 promise_rejects_js(t, RangeError, writer.closed, 'closed should reject'), 146 promise_rejects_js(t, RangeError, ts.readable.getReader().closed, 'readable closed should reject') 147 ]); 148 }); 149}, 'a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() ' + 150 'catches the exception'); 151