gecko-dev/testing/web-platform/tests/streams/readable-byte-streams/general.any.js
Jason Orendorff 47519c94b2 Bug 1513570 - Part 1: Adapt stream tests to run in the shell. r=Ms2ger
We don't support byte streams, transform streams, writable streams, or piping
yet, but we will, and in the meantime our own meta files disable those tests
for us.

Differential Revision: https://phabricator.services.mozilla.com/D14314

--HG--
extra : moz-landing-system : lando
2018-12-14 18:14:56 +00:00

2121 lines
64 KiB
JavaScript

// META: global=worker,jsshell
// META: script=../resources/rs-utils.js
// META: script=../resources/test-utils.js
'use strict';
const error1 = new Error('error1');
error1.name = 'error1';
test(() => {
assert_throws(new TypeError(), () => new ReadableStream().getReader({ mode: 'byob' }));
}, 'getReader({mode: "byob"}) throws on non-bytes streams');
test(() => {
// Constructing ReadableStream with an empty underlying byte source object as parameter shouldn't throw.
new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' });
// Constructor must perform ToString(type).
new ReadableStream({ type: { toString() {return 'bytes';} } })
.getReader({ mode: 'byob' });
new ReadableStream({ type: { toString: null, valueOf() {return 'bytes';} } })
.getReader({ mode: 'byob' });
}, 'ReadableStream with byte source can be constructed with no errors');
test(() => {
const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
const rs = new ReadableStream({ type: 'bytes' });
let reader = rs.getReader({ mode: { toString() { return 'byob'; } } });
assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader');
reader.releaseLock();
reader = rs.getReader({ mode: { toString: null, valueOf() {return 'byob';} } });
assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader');
reader.releaseLock();
reader = rs.getReader({ mode: 'byob', notmode: 'ignored' });
assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader');
}, 'getReader({mode}) must perform ToString()');
promise_test(() => {
let startCalled = false;
let startCalledBeforePull = false;
let desiredSize;
let controller;
let resolveTestPromise;
const testPromise = new Promise(resolve => {
resolveTestPromise = resolve;
});
new ReadableStream({
start(c) {
controller = c;
startCalled = true;
},
pull() {
startCalledBeforePull = startCalled;
desiredSize = controller.desiredSize;
resolveTestPromise();
},
type: 'bytes'
}, {
highWaterMark: 256
});
return testPromise.then(() => {
assert_true(startCalledBeforePull, 'start should be called before pull');
assert_equals(desiredSize, 256, 'desiredSize should equal highWaterMark');
});
}, 'ReadableStream with byte source: Construct and expect start and pull being called');
promise_test(() => {
let pullCount = 0;
let checkedNoPull = false;
let resolveTestPromise;
const testPromise = new Promise(resolve => {
resolveTestPromise = resolve;
});
let resolveStartPromise;
new ReadableStream({
start() {
return new Promise(resolve => {
resolveStartPromise = resolve;
});
},
pull() {
if (checkedNoPull) {
resolveTestPromise();
}
++pullCount;
},
type: 'bytes'
}, {
highWaterMark: 256
});
Promise.resolve().then(() => {
assert_equals(pullCount, 0);
checkedNoPull = true;
resolveStartPromise();
});
return testPromise;
}, 'ReadableStream with byte source: No automatic pull call if start doesn\'t finish');
promise_test(t => {
new ReadableStream({
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
}, {
highWaterMark: 0
});
return Promise.resolve();
}, 'ReadableStream with byte source: Construct with highWaterMark of 0');
test(() => {
new ReadableStream({
start(c) {
assert_equals(c.desiredSize, 10, 'desiredSize must start at the highWaterMark');
c.close();
assert_equals(c.desiredSize, 0, 'after closing, desiredSize must be 0');
},
type: 'bytes'
}, {
highWaterMark: 10
});
}, 'ReadableStream with byte source: desiredSize when closed');
test(() => {
new ReadableStream({
start(c) {
assert_equals(c.desiredSize, 10, 'desiredSize must start at the highWaterMark');
c.error();
assert_equals(c.desiredSize, null, 'after erroring, desiredSize must be null');
},
type: 'bytes'
}, {
highWaterMark: 10
});
}, 'ReadableStream with byte source: desiredSize when errored');
promise_test(t => {
const stream = new ReadableStream({
type: 'bytes'
});
const reader = stream.getReader();
reader.releaseLock();
return promise_rejects(t, new TypeError(), reader.closed, 'closed must reject');
}, 'ReadableStream with byte source: getReader(), then releaseLock()');
promise_test(t => {
const stream = new ReadableStream({
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
reader.releaseLock();
return promise_rejects(t, new TypeError(), reader.closed, 'closed must reject');
}, 'ReadableStream with byte source: getReader() with mode set to byob, then releaseLock()');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
c.close();
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader();
return reader.closed.then(() => {
assert_throws(new TypeError(), () => stream.getReader(), 'getReader() must throw');
});
}, 'ReadableStream with byte source: Test that closing a stream does not release a reader automatically');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
c.close();
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.closed.then(() => {
assert_throws(new TypeError(), () => stream.getReader({ mode: 'byob' }), 'getReader() must throw');
});
}, 'ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
c.error(error1);
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader();
return promise_rejects(t, error1, reader.closed, 'closed must reject').then(() => {
assert_throws(new TypeError(), () => stream.getReader(), 'getReader() must throw');
});
}, 'ReadableStream with byte source: Test that erroring a stream does not release a reader automatically');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
c.error(error1);
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, error1, reader.closed, 'closed must reject').then(() => {
assert_throws(new TypeError(), () => stream.getReader({ mode: 'byob' }), 'getReader() must throw');
});
}, 'ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically');
test(() => {
const stream = new ReadableStream({
type: 'bytes'
});
const reader = stream.getReader();
reader.read();
assert_throws(new TypeError(), () => reader.releaseLock(), 'reader.releaseLock() must throw');
}, 'ReadableStream with byte source: releaseLock() on ReadableStreamReader with pending read() must throw');
promise_test(() => {
let pullCount = 0;
const stream = new ReadableStream({
pull() {
++pullCount;
},
type: 'bytes'
}, {
highWaterMark: 8
});
stream.getReader();
assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream');
return Promise.resolve().then(() => {
assert_equals(pullCount, 1, 'pull must be invoked');
});
}, 'ReadableStream with byte source: Automatic pull() after start()');
promise_test(() => {
let pullCount = 0;
const stream = new ReadableStream({
pull() {
++pullCount;
},
type: 'bytes'
}, {
highWaterMark: 0
});
const reader = stream.getReader();
reader.read();
assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream');
return Promise.resolve().then(() => {
assert_equals(pullCount, 1, 'pull must be invoked');
});
}, 'ReadableStream with byte source: Automatic pull() after start() and read()');
// View buffers are detached after pull() returns, so record the information at the time that pull() was called.
function extractViewInfo(view) {
return {
constructor: view.constructor,
bufferByteLength: view.buffer.byteLength,
byteOffset: view.byteOffset,
byteLength: view.byteLength
};
}
promise_test(() => {
let pullCount = 0;
let controller;
const byobRequests = [];
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
const byobRequest = controller.byobRequest;
const view = byobRequest.view;
byobRequests[pullCount] = {
defined: byobRequest !== undefined,
viewDefined: view !== undefined,
viewInfo: extractViewInfo(view)
};
if (pullCount === 0) {
view[0] = 0x01;
byobRequest.respond(1);
} else if (pullCount === 1) {
view[0] = 0x02;
view[1] = 0x03;
byobRequest.respond(2);
}
++pullCount;
},
type: 'bytes',
autoAllocateChunkSize: 16
}, {
highWaterMark: 0
});
const reader = stream.getReader();
const p0 = reader.read();
const p1 = reader.read();
assert_equals(pullCount, 0, 'No pull() as start() just finished and is not yet reflected to the state of the stream');
return Promise.resolve().then(() => {
assert_equals(pullCount, 1, 'pull() must have been invoked once');
const byobRequest = byobRequests[0];
assert_true(byobRequest.defined, 'first byobRequest must not be undefined');
assert_true(byobRequest.viewDefined, 'first byobRequest.view must not be undefined');
const viewInfo = byobRequest.viewInfo;
assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
assert_equals(viewInfo.bufferByteLength, 16, 'first view.buffer.byteLength should be 16');
assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
assert_equals(viewInfo.byteLength, 16, 'first view.byteLength should be 16');
return p0;
}).then(result => {
assert_equals(pullCount, 2, 'pull() must have been invoked twice');
const value = result.value;
assert_not_equals(value, undefined, 'first read should have a value');
assert_equals(value.constructor, Uint8Array, 'first value should be a Uint8Array');
assert_equals(value.buffer.byteLength, 16, 'first value.buffer.byteLength should be 16');
assert_equals(value.byteOffset, 0, 'first value.byteOffset should be 0');
assert_equals(value.byteLength, 1, 'first value.byteLength should be 1');
assert_equals(value[0], 0x01, 'first value[0] should be 0x01');
const byobRequest = byobRequests[1];
assert_true(byobRequest.defined, 'second byobRequest must not be undefined');
assert_true(byobRequest.viewDefined, 'second byobRequest.view must not be undefined');
const viewInfo = byobRequest.viewInfo;
assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
assert_equals(viewInfo.bufferByteLength, 16, 'second view.buffer.byteLength should be 16');
assert_equals(viewInfo.byteOffset, 0, 'second view.byteOffset should be 0');
assert_equals(viewInfo.byteLength, 16, 'second view.byteLength should be 16');
return p1;
}).then(result => {
assert_equals(pullCount, 2, 'pull() should only be invoked twice');
const value = result.value;
assert_not_equals(value, undefined, 'second read should have a value');
assert_equals(value.constructor, Uint8Array, 'second value should be a Uint8Array');
assert_equals(value.buffer.byteLength, 16, 'second value.buffer.byteLength should be 16');
assert_equals(value.byteOffset, 0, 'second value.byteOffset should be 0');
assert_equals(value.byteLength, 2, 'second value.byteLength should be 2');
assert_equals(value[0], 0x02, 'second value[0] should be 0x02');
assert_equals(value[1], 0x03, 'second value[1] should be 0x03');
});
}, 'ReadableStream with byte source: autoAllocateChunkSize');
promise_test(() => {
let pullCount = 0;
let controller;
const byobRequests = [];
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
const byobRequest = controller.byobRequest;
const view = byobRequest.view;
byobRequests[pullCount] = {
defined: byobRequest !== undefined,
viewDefined: view !== undefined,
viewInfo: extractViewInfo(view)
};
if (pullCount === 0) {
view[0] = 0x01;
byobRequest.respond(1);
} else if (pullCount === 1) {
view[0] = 0x02;
view[1] = 0x03;
byobRequest.respond(2);
}
++pullCount;
},
type: 'bytes',
autoAllocateChunkSize: 16
}, {
highWaterMark: 0
});
const reader = stream.getReader();
return reader.read().then(result => {
const value = result.value;
assert_not_equals(value, undefined, 'first read should have a value');
assert_equals(value.constructor, Uint8Array, 'first value should be a Uint8Array');
assert_equals(value.buffer.byteLength, 16, 'first value.buffer.byteLength should be 16');
assert_equals(value.byteOffset, 0, 'first value.byteOffset should be 0');
assert_equals(value.byteLength, 1, 'first value.byteLength should be 1');
assert_equals(value[0], 0x01, 'first value[0] should be 0x01');
const byobRequest = byobRequests[0];
assert_true(byobRequest.defined, 'first byobRequest must not be undefined');
assert_true(byobRequest.viewDefined, 'first byobRequest.view must not be undefined');
const viewInfo = byobRequest.viewInfo;
assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
assert_equals(viewInfo.bufferByteLength, 16, 'first view.buffer.byteLength should be 16');
assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
assert_equals(viewInfo.byteLength, 16, 'first view.byteLength should be 16');
reader.releaseLock();
const byobReader = stream.getReader({ mode: 'byob' });
return byobReader.read(new Uint8Array(32));
}).then(result => {
const value = result.value;
assert_not_equals(value, undefined, 'second read should have a value');
assert_equals(value.constructor, Uint8Array, 'second value should be a Uint8Array');
assert_equals(value.buffer.byteLength, 32, 'second value.buffer.byteLength should be 32');
assert_equals(value.byteOffset, 0, 'second value.byteOffset should be 0');
assert_equals(value.byteLength, 2, 'second value.byteLength should be 2');
assert_equals(value[0], 0x02, 'second value[0] should be 0x02');
assert_equals(value[1], 0x03, 'second value[1] should be 0x03');
const byobRequest = byobRequests[1];
assert_true(byobRequest.defined, 'second byobRequest must not be undefined');
assert_true(byobRequest.viewDefined, 'second byobRequest.view must not be undefined');
const viewInfo = byobRequest.viewInfo;
assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
assert_equals(viewInfo.bufferByteLength, 32, 'second view.buffer.byteLength should be 32');
assert_equals(viewInfo.byteOffset, 0, 'second view.byteOffset should be 0');
assert_equals(viewInfo.byteLength, 32, 'second view.byteLength should be 32');
assert_equals(pullCount, 2, 'pullCount should be 2');
});
}, 'ReadableStream with byte source: Mix of auto allocate and BYOB');
promise_test(() => {
let pullCount = 0;
const stream = new ReadableStream({
pull() {
++pullCount;
},
type: 'bytes'
}, {
highWaterMark: 0
});
const reader = stream.getReader();
reader.read(new Uint8Array(8));
assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream');
return Promise.resolve().then(() => {
assert_equals(pullCount, 1, 'pull must be invoked');
});
}, 'ReadableStream with byte source: Automatic pull() after start() and read(view)');
promise_test(() => {
let pullCount = 0;
let controller;
let desiredSizeInStart;
let desiredSizeInPull;
const stream = new ReadableStream({
start(c) {
c.enqueue(new Uint8Array(16));
desiredSizeInStart = c.desiredSize;
controller = c;
},
pull() {
++pullCount;
if (pullCount === 1) {
desiredSizeInPull = controller.desiredSize;
}
},
type: 'bytes'
}, {
highWaterMark: 8
});
return Promise.resolve().then(() => {
assert_equals(pullCount, 0, 'No pull as the queue was filled by start()');
assert_equals(desiredSizeInStart, -8, 'desiredSize after enqueue() in start()');
const reader = stream.getReader();
const promise = reader.read();
assert_equals(pullCount, 1, 'The first pull() should be made on read()');
assert_equals(desiredSizeInPull, 8, 'desiredSize in pull()');
return promise.then(result => {
assert_equals(result.done, false, 'result.done');
const view = result.value;
assert_equals(view.constructor, Uint8Array, 'view.constructor');
assert_equals(view.buffer.byteLength, 16, 'view.buffer');
assert_equals(view.byteOffset, 0, 'view.byteOffset');
assert_equals(view.byteLength, 16, 'view.byteLength');
});
});
}, 'ReadableStream with byte source: enqueue(), getReader(), then read()');
promise_test(() => {
let controller;
const stream = new ReadableStream({
start(c) {
controller = c;
},
type: 'bytes'
});
const reader = stream.getReader();
const promise = reader.read().then(result => {
assert_equals(result.done, false);
const view = result.value;
assert_equals(view.constructor, Uint8Array);
assert_equals(view.buffer.byteLength, 1);
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 1);
});
controller.enqueue(new Uint8Array(1));
return promise;
}, 'ReadableStream with byte source: Push source that doesn\'t understand pull signal');
test(() => {
assert_throws(new TypeError(), () => new ReadableStream({
pull: 'foo',
type: 'bytes'
}), 'constructor should throw');
}, 'ReadableStream with byte source: pull() function is not callable');
promise_test(() => {
const stream = new ReadableStream({
start(c) {
c.enqueue(new Uint16Array(16));
},
type: 'bytes'
});
const reader = stream.getReader();
return reader.read().then(result => {
assert_equals(result.done, false);
const view = result.value;
assert_equals(view.constructor, Uint8Array);
assert_equals(view.buffer.byteLength, 32);
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 32);
});
}, 'ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read()');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
const view = new Uint8Array(16);
view[0] = 0x01;
view[8] = 0x02;
c.enqueue(view);
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const byobReader = stream.getReader({ mode: 'byob' });
return byobReader.read(new Uint8Array(8)).then(result => {
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.constructor, Uint8Array, 'value.constructor');
assert_equals(view.buffer.byteLength, 8, 'value.buffer.byteLength');
assert_equals(view.byteOffset, 0, 'value.byteOffset');
assert_equals(view.byteLength, 8, 'value.byteLength');
assert_equals(view[0], 0x01);
byobReader.releaseLock();
const reader = stream.getReader();
return reader.read();
}).then(result => {
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.constructor, Uint8Array, 'value.constructor');
assert_equals(view.buffer.byteLength, 16, 'value.buffer.byteLength');
assert_equals(view.byteOffset, 8, 'value.byteOffset');
assert_equals(view.byteLength, 8, 'value.byteLength');
assert_equals(view[0], 0x02);
});
}, 'ReadableStream with byte source: enqueue(), read(view) partially, then read()');
promise_test(t => {
let controller;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader();
controller.enqueue(new Uint8Array(16));
controller.close();
return reader.read().then(result => {
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.byteOffset, 0, 'byteOffset');
assert_equals(view.byteLength, 16, 'byteLength');
return reader.read();
}).then(result => {
assert_equals(result.done, true, 'done');
assert_equals(result.value, undefined, 'value');
});
}, 'ReadableStream with byte source: getReader(), enqueue(), close(), then read()');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
c.enqueue(new Uint8Array(16));
c.close();
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader();
return reader.read().then(result => {
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.byteOffset, 0, 'byteOffset');
assert_equals(view.byteLength, 16, 'byteLength');
return reader.read();
}).then(result => {
assert_equals(result.done, true, 'done');
assert_equals(result.value, undefined, 'value');
});
}, 'ReadableStream with byte source: enqueue(), close(), getReader(), then read()');
promise_test(() => {
let controller;
let byobRequest;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
controller.enqueue(new Uint8Array(16));
byobRequest = controller.byobRequest;
},
type: 'bytes'
});
const reader = stream.getReader();
return reader.read().then(result => {
assert_equals(result.done, false, 'done');
assert_equals(result.value.byteLength, 16, 'byteLength');
assert_equals(byobRequest, undefined, 'byobRequest must be undefined');
});
}, 'ReadableStream with byte source: Respond to pull() by enqueue()');
promise_test(() => {
let pullCount = 0;
let controller;
let byobRequest;
const desiredSizes = [];
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
byobRequest = controller.byobRequest;
desiredSizes.push(controller.desiredSize);
controller.enqueue(new Uint8Array(1));
desiredSizes.push(controller.desiredSize);
controller.enqueue(new Uint8Array(1));
desiredSizes.push(controller.desiredSize);
++pullCount;
},
type: 'bytes'
}, {
highWaterMark: 0
});
const reader = stream.getReader();
const p0 = reader.read();
const p1 = reader.read();
const p2 = reader.read();
// Respond to the first pull call.
controller.enqueue(new Uint8Array(1));
assert_equals(pullCount, 0, 'pullCount after the enqueue() outside pull');
return Promise.all([p0, p1, p2]).then(result => {
assert_equals(pullCount, 1, 'pullCount after completion of all read()s');
assert_equals(result[0].done, false, 'result[0].done');
assert_equals(result[0].value.byteLength, 1, 'result[0].value.byteLength');
assert_equals(result[1].done, false, 'result[1].done');
assert_equals(result[1].value.byteLength, 1, 'result[1].value.byteLength');
assert_equals(result[2].done, false, 'result[2].done');
assert_equals(result[2].value.byteLength, 1, 'result[2].value.byteLength');
assert_equals(byobRequest, undefined, 'byobRequest should be undefined');
assert_equals(desiredSizes[0], 0, 'desiredSize on pull should be 0');
assert_equals(desiredSizes[1], 0, 'desiredSize after 1st enqueue() should be 0');
assert_equals(desiredSizes[2], 0, 'desiredSize after 2nd enqueue() should be 0');
assert_equals(pullCount, 1, 'pull() should only be called once');
});
}, 'ReadableStream with byte source: Respond to pull() by enqueue() asynchronously');
promise_test(() => {
let pullCount = 0;
let byobRequest;
const desiredSizes = [];
const stream = new ReadableStream({
pull(c) {
byobRequest = c.byobRequest;
desiredSizes.push(c.desiredSize);
if (pullCount < 3) {
c.enqueue(new Uint8Array(1));
} else {
c.close();
}
++pullCount;
},
type: 'bytes'
}, {
highWaterMark: 256
});
const reader = stream.getReader();
const p0 = reader.read();
const p1 = reader.read();
const p2 = reader.read();
assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream');
return Promise.all([p0, p1, p2]).then(result => {
assert_equals(pullCount, 4, 'pullCount after completion of all read()s');
assert_equals(result[0].done, false, 'result[0].done');
assert_equals(result[0].value.byteLength, 1, 'result[0].value.byteLength');
assert_equals(result[1].done, false, 'result[1].done');
assert_equals(result[1].value.byteLength, 1, 'result[1].value.byteLength');
assert_equals(result[2].done, false, 'result[2].done');
assert_equals(result[2].value.byteLength, 1, 'result[2].value.byteLength');
assert_equals(byobRequest, undefined, 'byobRequest should be undefined');
assert_equals(desiredSizes[0], 256, 'desiredSize on pull should be 256');
assert_equals(desiredSizes[1], 256, 'desiredSize after 1st enqueue() should be 256');
assert_equals(desiredSizes[2], 256, 'desiredSize after 2nd enqueue() should be 256');
assert_equals(desiredSizes[3], 256, 'desiredSize after 3rd enqueue() should be 256');
});
}, 'ReadableStream with byte source: Respond to multiple pull() by separate enqueue()');
promise_test(() => {
let controller;
let pullCount = 0;
const byobRequestDefined = [];
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
byobRequestDefined.push(controller.byobRequest !== undefined);
const view = controller.byobRequest.view;
view[0] = 0x01;
controller.byobRequest.respond(1);
byobRequestDefined.push(controller.byobRequest !== undefined);
++pullCount;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint8Array(1)).then(result => {
assert_equals(result.done, false, 'result.done');
assert_equals(result.value.byteLength, 1, 'result.value.byteLength');
assert_equals(result.value[0], 0x01, 'result.value[0]');
assert_equals(pullCount, 1, 'pull() should be called only once');
assert_true(byobRequestDefined[0], 'byobRequest must not be undefined before respond()');
assert_false(byobRequestDefined[1], 'byobRequest must be undefined after respond()');
});
}, 'ReadableStream with byte source: read(view), then respond()');
promise_test(() => {
let controller;
let pullCount = 0;
const byobRequestDefined = [];
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
byobRequestDefined.push(controller.byobRequest !== undefined);
// Emulate ArrayBuffer transfer by just creating a new ArrayBuffer and pass it. By checking the result of
// read(view), we test that the respond()'s buffer argument is working correctly.
//
// A real implementation of the underlying byte source would transfer controller.byobRequest.view.buffer into
// a new ArrayBuffer, then construct a view around it and write to it.
const transferredView = new Uint8Array(1);
transferredView[0] = 0x01;
controller.byobRequest.respondWithNewView(transferredView);
byobRequestDefined.push(controller.byobRequest !== undefined);
++pullCount;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint8Array(1)).then(result => {
assert_equals(result.done, false, 'result.done');
assert_equals(result.value.byteLength, 1, 'result.value.byteLength');
assert_equals(result.value[0], 0x01, 'result.value[0]');
assert_equals(pullCount, 1, 'pull() should be called only once');
assert_true(byobRequestDefined[0], 'byobRequest must not be undefined before respond()');
assert_false(byobRequestDefined[1], 'byobRequest must be undefined after respond()');
});
}, 'ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer');
promise_test(() => {
let controller;
let byobRequestWasDefined;
let incorrectRespondException;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
byobRequestWasDefined = controller.byobRequest !== undefined;
try {
controller.byobRequest.respond(2);
} catch (e) {
incorrectRespondException = e;
}
controller.byobRequest.respond(1);
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint8Array(1)).then(() => {
assert_true(byobRequestWasDefined, 'byobRequest should be defined');
assert_not_equals(incorrectRespondException, undefined, 'respond() must throw');
assert_equals(incorrectRespondException.name, 'RangeError', 'respond() must throw a RangeError');
});
}, 'ReadableStream with byte source: read(view), then respond() with too big value');
promise_test(() => {
let pullCount = 0;
let controller;
let byobRequest;
let viewInfo;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
++pullCount;
byobRequest = controller.byobRequest;
const view = byobRequest.view;
viewInfo = extractViewInfo(view);
view[0] = 0x01;
view[1] = 0x02;
view[2] = 0x03;
controller.byobRequest.respond(3);
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint16Array(2)).then(result => {
assert_equals(pullCount, 1);
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.byteOffset, 0, 'byteOffset');
assert_equals(view.byteLength, 2, 'byteLength');
assert_equals(view[0], 0x0201);
return reader.read(new Uint8Array(1));
}).then(result => {
assert_equals(pullCount, 1);
assert_not_equals(byobRequest, undefined, 'byobRequest must not be undefined');
assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array');
assert_equals(viewInfo.bufferByteLength, 4, 'view.buffer.byteLength should be 4');
assert_equals(viewInfo.byteOffset, 0, 'view.byteOffset should be 0');
assert_equals(viewInfo.byteLength, 4, 'view.byteLength should be 4');
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.byteOffset, 0, 'byteOffset');
assert_equals(view.byteLength, 1, 'byteLength');
assert_equals(view[0], 0x03);
});
}, 'ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte ' +
'remainder');
promise_test(t => {
const stream = new ReadableStream({
start(controller) {
const view = new Uint8Array(16);
view[15] = 0x01;
controller.enqueue(view);
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint8Array(16)).then(result => {
assert_equals(result.done, false);
const view = result.value;
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 16);
assert_equals(view[15], 0x01);
});
}, 'ReadableStream with byte source: enqueue(), getReader(), then read(view)');
promise_test(t => {
let cancelCount = 0;
let reason;
const passedReason = new TypeError('foo');
const stream = new ReadableStream({
start(c) {
c.enqueue(new Uint8Array(16));
},
pull: t.unreached_func('pull() should not be called'),
cancel(r) {
if (cancelCount === 0) {
reason = r;
}
++cancelCount;
},
type: 'bytes'
});
const reader = stream.getReader();
return reader.cancel(passedReason).then(result => {
assert_equals(result, undefined);
assert_equals(cancelCount, 1);
assert_equals(reason, passedReason, 'reason should equal the passed reason');
});
}, 'ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB)');
promise_test(t => {
let cancelCount = 0;
let reason;
const passedReason = new TypeError('foo');
const stream = new ReadableStream({
start(c) {
c.enqueue(new Uint8Array(16));
},
pull: t.unreached_func('pull() should not be called'),
cancel(r) {
if (cancelCount === 0) {
reason = r;
}
++cancelCount;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.cancel(passedReason).then(result => {
assert_equals(result, undefined);
assert_equals(cancelCount, 1);
assert_equals(reason, passedReason, 'reason should equal the passed reason');
});
}, 'ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB)');
promise_test(t => {
let cancelCount = 0;
let reason;
const passedReason = new TypeError('foo');
let controller;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull: t.unreached_func('pull() should not be called'),
cancel(r) {
if (cancelCount === 0) {
reason = r;
controller.byobRequest.respond(0);
}
++cancelCount;
return 'bar';
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
const readPromise = reader.read(new Uint8Array(1)).then(result => {
assert_equals(result.done, true);
});
const cancelPromise = reader.cancel(passedReason).then(result => {
assert_equals(result, undefined);
assert_equals(cancelCount, 1);
assert_equals(reason, passedReason, 'reason should equal the passed reason');
});
return Promise.all([readPromise, cancelPromise]);
}, 'ReadableStream with byte source: getReader(), read(view), then cancel()');
promise_test(() => {
let pullCount = 0;
let controller;
let byobRequest;
const viewInfos = [];
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
byobRequest = controller.byobRequest;
viewInfos.push(extractViewInfo(controller.byobRequest.view));
controller.enqueue(new Uint8Array(1));
viewInfos.push(extractViewInfo(controller.byobRequest.view));
++pullCount;
},
type: 'bytes'
});
return Promise.resolve().then(() => {
assert_equals(pullCount, 0, 'No pull() as no read(view) yet');
const reader = stream.getReader({ mode: 'byob' });
const promise = reader.read(new Uint16Array(1)).then(result => {
assert_equals(result.done, true, 'result.done');
assert_equals(result.value.constructor, Uint16Array, 'result.value');
});
assert_equals(pullCount, 1, '1 pull() should have been made in response to partial fill by enqueue()');
assert_not_equals(byobRequest, undefined, 'byobRequest should not be undefined');
assert_equals(viewInfos[0].byteLength, 2, 'byteLength before enqueue() shouild be 2');
assert_equals(viewInfos[1].byteLength, 1, 'byteLength after enqueue() should be 1');
reader.cancel();
// Tell that the buffer given via pull() is returned.
controller.byobRequest.respond(0);
assert_equals(pullCount, 1, 'pull() should only be called once');
return promise;
});
}, 'ReadableStream with byte source: cancel() with partially filled pending pull() request');
promise_test(() => {
let controller;
let byobRequest;
const stream = new ReadableStream({
start(c) {
const view = new Uint8Array(8);
view[7] = 0x01;
c.enqueue(view);
controller = c;
},
pull() {
byobRequest = controller.byobRequest;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
const buffer = new ArrayBuffer(16);
return reader.read(new Uint8Array(buffer, 8, 8)).then(result => {
assert_equals(result.done, false);
assert_equals(byobRequest, undefined, 'byobRequest must be undefined');
const view = result.value;
assert_equals(view.constructor, Uint8Array);
assert_equals(view.buffer.byteLength, 16);
assert_equals(view.byteOffset, 8);
assert_equals(view.byteLength, 8);
assert_equals(view[7], 0x01);
});
}, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully ' +
'covered by view');
promise_test(() => {
let controller;
let byobRequest;
const stream = new ReadableStream({
start(c) {
let view;
view = new Uint8Array(16);
view[15] = 123;
c.enqueue(view);
view = new Uint8Array(8);
view[7] = 111;
c.enqueue(view);
controller = c;
},
pull() {
byobRequest = controller.byobRequest;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint8Array(24)).then(result => {
assert_equals(result.done, false, 'done');
assert_equals(byobRequest, undefined, 'byobRequest must be undefined');
const view = result.value;
assert_equals(view.byteOffset, 0, 'byteOffset');
assert_equals(view.byteLength, 24, 'byteLength');
assert_equals(view[15], 123, 'Contents are set from the first chunk');
assert_equals(view[23], 111, 'Contents are set from the second chunk');
});
}, 'ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view)');
promise_test(() => {
let byobRequest;
const stream = new ReadableStream({
start(c) {
const view = new Uint8Array(16);
view[15] = 0x01;
c.enqueue(view);
},
pull(controller) {
byobRequest = controller.byobRequest;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint8Array(24)).then(result => {
assert_equals(result.done, false);
assert_equals(byobRequest, undefined, 'byobRequest must be undefined');
const view = result.value;
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 16);
assert_equals(view[15], 0x01);
});
}, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view');
promise_test(() => {
let byobRequest;
const stream = new ReadableStream({
start(c) {
const view = new Uint8Array(16);
view[7] = 0x01;
view[15] = 0x02;
c.enqueue(view);
},
pull(controller) {
byobRequest = controller.byobRequest;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint8Array(8)).then(result => {
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 8);
assert_equals(view[7], 0x01);
return reader.read(new Uint8Array(8));
}).then(result => {
assert_equals(result.done, false, 'done');
assert_equals(byobRequest, undefined, 'byobRequest must be undefined');
const view = result.value;
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 8);
assert_equals(view[7], 0x02);
});
}, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) with a smaller views');
promise_test(() => {
let controller;
let viewInfo;
const stream = new ReadableStream({
start(c) {
const view = new Uint8Array(1);
view[0] = 0xff;
c.enqueue(view);
controller = c;
},
pull() {
if (controller.byobRequest === undefined) {
return;
}
const view = controller.byobRequest.view;
viewInfo = extractViewInfo(view);
view[0] = 0xaa;
controller.byobRequest.respond(1);
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint16Array(1)).then(result => {
assert_equals(result.done, false);
const view = result.value;
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 2);
assert_equals(view[0], 0xaaff);
assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array');
assert_equals(viewInfo.bufferByteLength, 2, 'view.buffer.byteLength should be 2');
assert_equals(viewInfo.byteOffset, 1, 'view.byteOffset should be 1');
assert_equals(viewInfo.byteLength, 1, 'view.byteLength should be 1');
});
}, 'ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array');
promise_test(() => {
let pullCount = 0;
let controller;
let byobRequest;
let viewInfo;
let desiredSize;
const stream = new ReadableStream({
start(c) {
const view = new Uint8Array(3);
view[0] = 0x01;
view[2] = 0x02;
c.enqueue(view);
controller = c;
},
pull() {
byobRequest = controller.byobRequest;
const view = controller.byobRequest.view;
viewInfo = extractViewInfo(view);
view[0] = 0x03;
controller.byobRequest.respond(1);
desiredSize = controller.desiredSize;
++pullCount;
},
type: 'bytes'
});
// Wait for completion of the start method to be reflected.
return Promise.resolve().then(() => {
const reader = stream.getReader({ mode: 'byob' });
const promise = reader.read(new Uint16Array(2)).then(result => {
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.constructor, Uint16Array, 'constructor');
assert_equals(view.buffer.byteLength, 4, 'buffer.byteLength');
assert_equals(view.byteOffset, 0, 'byteOffset');
assert_equals(view.byteLength, 2, 'byteLength');
assert_equals(view[0], 0x0001, 'Contents are set');
const p = reader.read(new Uint16Array(1));
assert_equals(pullCount, 1);
return p;
}).then(result => {
assert_equals(result.done, false, 'done');
const view = result.value;
assert_equals(view.buffer.byteLength, 2, 'buffer.byteLength');
assert_equals(view.byteOffset, 0, 'byteOffset');
assert_equals(view.byteLength, 2, 'byteLength');
assert_equals(view[0], 0x0302, 'Contents are set');
assert_not_equals(byobRequest, undefined, 'byobRequest must not be undefined');
assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array');
assert_equals(viewInfo.bufferByteLength, 2, 'view.buffer.byteLength should be 2');
assert_equals(viewInfo.byteOffset, 1, 'view.byteOffset should be 1');
assert_equals(viewInfo.byteLength, 1, 'view.byteLength should be 1');
assert_equals(desiredSize, 0, 'desiredSize should be zero');
});
assert_equals(pullCount, 0);
return promise;
});
}, 'ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
const view = new Uint8Array(1);
view[0] = 0xff;
c.enqueue(view);
c.close();
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, new TypeError(), reader.read(new Uint16Array(1)), 'read(view) must fail')
.then(() => promise_rejects(t, new TypeError(), reader.closed, 'reader.closed should reject'));
}, 'ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must ' +
'fail');
promise_test(t => {
let controller;
const stream = new ReadableStream({
start(c) {
const view = new Uint8Array(1);
view[0] = 0xff;
c.enqueue(view);
controller = c;
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
const readPromise = reader.read(new Uint16Array(1));
assert_throws(new TypeError(), () => controller.close(), 'controller.close() must throw');
return promise_rejects(t, new TypeError(), readPromise, 'read(view) must fail')
.then(() => promise_rejects(t, new TypeError(), reader.closed, 'reader.closed must reject'));
}, 'ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with ' +
'Uint16Array');
test(() => {
let controller;
new ReadableStream({
start(c) {
controller = c;
},
type: 'bytes'
});
// Enqueue a chunk so that the stream doesn't get closed. This is to check duplicate close() calls are rejected
// even if the stream has not yet entered the closed state.
const view = new Uint8Array(1);
controller.enqueue(view);
controller.close();
assert_throws(new TypeError(), () => controller.close(), 'controller.close() must throw');
}, 'ReadableStream with byte source: Throw if close()-ed more than once');
test(() => {
let controller;
new ReadableStream({
start(c) {
controller = c;
},
type: 'bytes'
});
// Enqueue a chunk so that the stream doesn't get closed. This is to check enqueue() after close() is rejected
// even if the stream has not yet entered the closed state.
const view = new Uint8Array(1);
controller.enqueue(view);
controller.close();
assert_throws(new TypeError(), () => controller.enqueue(view), 'controller.close() must throw');
}, 'ReadableStream with byte source: Throw on enqueue() after close()');
promise_test(() => {
let controller;
let byobRequest;
let viewInfo;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
byobRequest = controller.byobRequest;
const view = controller.byobRequest.view;
viewInfo = extractViewInfo(view);
view[15] = 0x01;
controller.byobRequest.respond(16);
controller.close();
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint8Array(16)).then(result => {
assert_equals(result.done, false);
const view = result.value;
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 16);
assert_equals(view[15], 0x01);
return reader.read(new Uint8Array(16));
}).then(result => {
assert_equals(result.done, true);
const view = result.value;
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 0);
assert_not_equals(byobRequest, undefined, 'byobRequest must not be undefined');
assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array');
assert_equals(viewInfo.bufferByteLength, 16, 'view.buffer.byteLength should be 16');
assert_equals(viewInfo.byteOffset, 0, 'view.byteOffset should be 0');
assert_equals(viewInfo.byteLength, 16, 'view.byteLength should be 16');
});
}, 'ReadableStream with byte source: read(view), then respond() and close() in pull()');
promise_test(() => {
let pullCount = 0;
let controller;
const viewInfos = [];
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
if (controller.byobRequest === undefined) {
return;
}
for (let i = 0; i < 4; ++i) {
const view = controller.byobRequest.view;
viewInfos.push(extractViewInfo(view));
view[0] = 0x01;
controller.byobRequest.respond(1);
}
++pullCount;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return reader.read(new Uint32Array(1)).then(result => {
assert_equals(result.done, false);
const view = result.value;
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 4);
assert_equals(view[0], 0x01010101);
assert_equals(pullCount, 1, 'pull() should only be called once');
for (let i = 0; i < 4; ++i) {
assert_equals(viewInfos[i].constructor, Uint8Array, 'view.constructor should be Uint8Array');
assert_equals(viewInfos[i].bufferByteLength, 4, 'view.buffer.byteLength should be 4');
assert_equals(viewInfos[i].byteOffset, i, 'view.byteOffset should be i');
assert_equals(viewInfos[i].byteLength, 4 - i, 'view.byteLength should be 4 - i');
}
});
}, 'ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls');
promise_test(() => {
let pullCount = 0;
let controller;
let byobRequest;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
byobRequest = controller.byobRequest;
++pullCount;
},
type: 'bytes'
});
const reader = stream.getReader();
const p0 = reader.read().then(result => {
assert_equals(pullCount, 1);
controller.enqueue(new Uint8Array(2));
// Since the queue has data no less than HWM, no more pull.
assert_equals(pullCount, 1);
assert_equals(result.done, false);
const view = result.value;
assert_equals(view.constructor, Uint8Array);
assert_equals(view.buffer.byteLength, 1);
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 1);
});
assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled');
const p1 = reader.read().then(result => {
assert_equals(pullCount, 1);
assert_equals(result.done, false);
const view = result.value;
assert_equals(view.constructor, Uint8Array);
assert_equals(view.buffer.byteLength, 2);
assert_equals(view.byteOffset, 0);
assert_equals(view.byteLength, 2);
assert_equals(byobRequest, undefined, 'byobRequest must be undefined');
});
assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled');
controller.enqueue(new Uint8Array(1));
assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled');
return Promise.all([p0, p1]);
}, 'ReadableStream with byte source: read() twice, then enqueue() twice');
promise_test(t => {
let controller;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
const p0 = reader.read(new Uint8Array(16)).then(result => {
assert_equals(result.done, true, '1st read: done');
const view = result.value;
assert_equals(view.buffer.byteLength, 16, '1st read: buffer.byteLength');
assert_equals(view.byteOffset, 0, '1st read: byteOffset');
assert_equals(view.byteLength, 0, '1st read: byteLength');
});
const p1 = reader.read(new Uint8Array(32)).then(result => {
assert_equals(result.done, true, '2nd read: done');
const view = result.value;
assert_equals(view.buffer.byteLength, 32, '2nd read: buffer.byteLength');
assert_equals(view.byteOffset, 0, '2nd read: byteOffset');
assert_equals(view.byteLength, 0, '2nd read: byteLength');
});
controller.close();
controller.byobRequest.respond(0);
return Promise.all([p0, p1]);
}, 'ReadableStream with byte source: Multiple read(view), close() and respond()');
promise_test(t => {
let controller;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
const p0 = reader.read(new Uint8Array(16)).then(result => {
assert_equals(result.done, false, '1st read: done');
const view = result.value;
assert_equals(view.buffer.byteLength, 16, '1st read: buffer.byteLength');
assert_equals(view.byteOffset, 0, '1st read: byteOffset');
assert_equals(view.byteLength, 16, '1st read: byteLength');
});
const p1 = reader.read(new Uint8Array(16)).then(result => {
assert_equals(result.done, false, '2nd read: done');
const view = result.value;
assert_equals(view.buffer.byteLength, 16, '2nd read: buffer.byteLength');
assert_equals(view.byteOffset, 0, '2nd read: byteOffset');
assert_equals(view.byteLength, 8, '2nd read: byteLength');
});
controller.enqueue(new Uint8Array(24));
return Promise.all([p0, p1]);
}, 'ReadableStream with byte source: Multiple read(view), big enqueue()');
promise_test(t => {
let controller;
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
let bytesRead = 0;
function pump() {
return reader.read(new Uint8Array(7)).then(result => {
if (result.done) {
assert_equals(bytesRead, 1024);
return undefined;
}
bytesRead += result.value.byteLength;
return pump();
});
}
const promise = pump();
controller.enqueue(new Uint8Array(512));
controller.enqueue(new Uint8Array(512));
controller.close();
return promise;
}, 'ReadableStream with byte source: Multiple read(view) and multiple enqueue()');
promise_test(t => {
let byobRequest;
const stream = new ReadableStream({
pull(controller) {
byobRequest = controller.byobRequest;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, new TypeError(), reader.read(), 'read() must fail')
.then(() => assert_equals(byobRequest, undefined, 'byobRequest must be undefined'));
}, 'ReadableStream with byte source: read(view) with passing undefined as view must fail');
promise_test(t => {
let byobRequest;
const stream = new ReadableStream({
pull(controller) {
byobRequest = controller.byobRequest;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, new TypeError(), reader.read(new Uint8Array(0)), 'read(view) must fail')
.then(() => assert_equals(byobRequest, undefined, 'byobRequest must be undefined'));
}, 'ReadableStream with byte source: read(view) with zero-length view must fail');
promise_test(t => {
const stream = new ReadableStream({
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, new TypeError(), reader.read({}), 'read(view) must fail');
}, 'ReadableStream with byte source: read(view) with passing an empty object as view must fail');
promise_test(t => {
const stream = new ReadableStream({
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, new TypeError(),
reader.read({ buffer: new ArrayBuffer(10), byteOffset: 0, byteLength: 10 }),
'read(view) must fail');
}, 'ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
c.error(error1);
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader();
return promise_rejects(t, error1, reader.read(), 'read() must fail');
}, 'ReadableStream with byte source: read() on an errored stream');
promise_test(t => {
let controller;
const stream = new ReadableStream({
start(c) {
controller = c;
},
type: 'bytes'
});
const reader = stream.getReader();
const promise = promise_rejects(t, error1, reader.read(), 'read() must fail');
controller.error(error1);
return promise;
}, 'ReadableStream with byte source: read(), then error()');
promise_test(t => {
const stream = new ReadableStream({
start(c) {
c.error(error1);
},
pull: t.unreached_func('pull() should not be called'),
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, error1, reader.read(new Uint8Array(1)), 'read() must fail');
}, 'ReadableStream with byte source: read(view) on an errored stream');
promise_test(t => {
let controller;
const stream = new ReadableStream({
start(c) {
controller = c;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
const promise = promise_rejects(t, error1, reader.read(new Uint8Array(1)), 'read() must fail');
controller.error(error1);
return promise;
}, 'ReadableStream with byte source: read(view), then error()');
promise_test(t => {
let controller;
let byobRequest;
const testError = new TypeError('foo');
const stream = new ReadableStream({
start(c) {
controller = c;
},
pull() {
byobRequest = controller.byobRequest;
throw testError;
},
type: 'bytes'
});
const reader = stream.getReader();
const promise = promise_rejects(t, testError, reader.read(), 'read() must fail');
return promise_rejects(t, testError, promise.then(() => reader.closed))
.then(() => assert_equals(byobRequest, undefined, 'byobRequest must be undefined'));
}, 'ReadableStream with byte source: Throwing in pull function must error the stream');
promise_test(t => {
let byobRequest;
const stream = new ReadableStream({
pull(controller) {
byobRequest = controller.byobRequest;
controller.error(error1);
throw new TypeError('foo');
},
type: 'bytes'
});
const reader = stream.getReader();
return promise_rejects(t, error1, reader.read(), 'read() must fail')
.then(() => promise_rejects(t, error1, reader.closed, 'closed must fail'))
.then(() => assert_equals(byobRequest, undefined, 'byobRequest must be undefined'));
}, 'ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is ' +
'errored in it');
promise_test(t => {
let byobRequest;
const testError = new TypeError('foo');
const stream = new ReadableStream({
pull(controller) {
byobRequest = controller.byobRequest;
throw testError;
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, testError, reader.read(new Uint8Array(1)), 'read(view) must fail')
.then(() => promise_rejects(t, testError, reader.closed, 'reader.closed must reject'))
.then(() => assert_not_equals(byobRequest, undefined, 'byobRequest must not be undefined'));
}, 'ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream');
promise_test(t => {
let byobRequest;
const stream = new ReadableStream({
pull(controller) {
byobRequest = controller.byobRequest;
controller.error(error1);
throw new TypeError('foo');
},
type: 'bytes'
});
const reader = stream.getReader({ mode: 'byob' });
return promise_rejects(t, error1, reader.read(new Uint8Array(1)), 'read(view) must fail')
.then(() => promise_rejects(t, error1, reader.closed, 'closed must fail'))
.then(() => assert_not_equals(byobRequest, undefined, 'byobRequest must not be undefined'));
}, 'ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is ' +
'errored in it');
promise_test(() => {
let byobRequest;
const rs = new ReadableStream({
pull(controller) {
byobRequest = controller.byobRequest;
byobRequest.respond(4);
},
type: 'bytes'
});
const reader = rs.getReader({ mode: 'byob' });
const view = new Uint8Array(16);
return reader.read(view).then(() => {
assert_throws(new TypeError(), () => byobRequest.respond(4), 'respond() should throw a TypeError');
});
}, 'calling respond() twice on the same byobRequest should throw');
promise_test(() => {
let byobRequest;
const newView = () => new Uint8Array(16);
const rs = new ReadableStream({
pull(controller) {
byobRequest = controller.byobRequest;
byobRequest.respondWithNewView(newView());
},
type: 'bytes'
});
const reader = rs.getReader({ mode: 'byob' });
return reader.read(newView()).then(() => {
assert_throws(new TypeError(), () => byobRequest.respondWithNewView(newView()),
'respondWithNewView() should throw a TypeError');
});
}, 'calling respondWithNewView() twice on the same byobRequest should throw');
promise_test(() => {
let byobRequest;
let resolvePullCalledPromise;
const pullCalledPromise = new Promise(resolve => {
resolvePullCalledPromise = resolve;
});
let resolvePull;
const rs = new ReadableStream({
pull(controller) {
byobRequest = controller.byobRequest;
resolvePullCalledPromise();
return new Promise(resolve => {
resolvePull = resolve;
});
},
type: 'bytes'
});
const reader = rs.getReader({ mode: 'byob' });
const readPromise = reader.read(new Uint8Array(16));
return pullCalledPromise.then(() => {
const cancelPromise = reader.cancel('meh');
resolvePull();
byobRequest.respond(0);
return Promise.all([readPromise, cancelPromise]).then(() => {
assert_throws(new TypeError(), () => byobRequest.respond(0), 'respond() should throw');
});
});
}, 'calling respond(0) twice on the same byobRequest should throw even when closed');
promise_test(() => {
let resolvePullCalledPromise;
const pullCalledPromise = new Promise(resolve => {
resolvePullCalledPromise = resolve;
});
let resolvePull;
const rs = new ReadableStream({
pull() {
resolvePullCalledPromise();
return new Promise(resolve => {
resolvePull = resolve;
});
},
type: 'bytes'
});
const reader = rs.getReader({ mode: 'byob' });
reader.read(new Uint8Array(16));
return pullCalledPromise.then(() => {
resolvePull();
return delay(0).then(() => {
assert_throws(new TypeError(), () => reader.releaseLock(), 'releaseLock() should throw');
});
});
}, 'pull() resolving should not make releaseLock() possible');
promise_test(() => {
// Tests https://github.com/whatwg/streams/issues/686
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 128,
start(c) {
controller = c;
},
type: 'bytes'
});
const readPromise = rs.getReader().read();
const br = controller.byobRequest;
controller.close();
br.respond(0);
return readPromise;
}, 'ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction');
test(() => {
const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
const stream = new ReadableStream({ type: 'bytes' });
new ReadableStreamBYOBReader(stream);
}, 'ReadableStreamBYOBReader can be constructed directly');
test(() => {
const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
assert_throws(new TypeError(), () => new ReadableStreamBYOBReader({}), 'constructor must throw');
}, 'ReadableStreamBYOBReader constructor requires a ReadableStream argument');
test(() => {
const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
const stream = new ReadableStream({ type: 'bytes' });
stream.getReader();
assert_throws(new TypeError(), () => new ReadableStreamBYOBReader(stream), 'constructor must throw');
}, 'ReadableStreamBYOBReader constructor requires an unlocked ReadableStream');
test(() => {
const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
const stream = new ReadableStream();
assert_throws(new TypeError(), () => new ReadableStreamBYOBReader(stream), 'constructor must throw');
}, 'ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes"');
test(() => {
assert_throws(new RangeError(), () => new ReadableStream({ type: 'bytes' }, {
size() {
return 1;
}
}), 'constructor should throw for size function');
assert_throws(new RangeError(), () => new ReadableStream({ type: 'bytes' }, { size: null }),
'constructor should throw for size defined');
assert_throws(new RangeError(),
() => new ReadableStream({ type: 'bytes' }, new CountQueuingStrategy({ highWaterMark: 1 })),
'constructor should throw when strategy is CountQueuingStrategy');
assert_throws(new RangeError(),
() => new ReadableStream({ type: 'bytes' }, new ByteLengthQueuingStrategy({ highWaterMark: 512 })),
'constructor should throw when strategy is ByteLengthQueuingStrategy');
class HasSizeMethod {
size() {}
}
assert_throws(new RangeError(), () => new ReadableStream({ type: 'bytes' }, new HasSizeMethod()),
'constructor should throw when size on the prototype chain');
}, 'ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"');