blob: 57a4117bc54be87729e0e3c44331cea920c68b07 [file] [log] [blame]
'use strict';
if (self.importScripts) {
self.importScripts('../resources/testharness.js');
}
test(() => {
const methods = ['constructor', 'respond', 'respondWithNewView'];
const properties = methods.concat(['view']).sort();
let controller;
// FIXME: Remove next line when bug https://bugs.webkit.org/show_bug.cgi?id=167697
// is fixed. For the moment, so that test may pass, we have to insert a reference
// to Uint8Array here (otherwise, the private variable cannot be resolved).
const d = new Uint8Array(1);
// Specifying autoAllocateChunkSize and calling read() are steps that allow
// getting a ReadableStreamBYOBRequest returned instead of undefined. The
// purpose here is just to get such an object.
const rs = new ReadableStream({
autoAllocateChunkSize: 128,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
const proto = Object.getPrototypeOf(byobReq);
assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties);
for (const m of methods) {
const propDesc = Object.getOwnPropertyDescriptor(proto, m);
assert_equals(propDesc.enumerable, false, 'method should be non-enumerable');
assert_equals(propDesc.configurable, true, 'method should be configurable');
assert_equals(propDesc.writable, true, 'method should be writable');
assert_equals(typeof byobReq[m], 'function', 'should have be a method');
}
const viewPropDesc = Object.getOwnPropertyDescriptor(proto, 'view');
assert_equals(viewPropDesc.enumerable, false, 'view should be non-enumerable');
assert_equals(viewPropDesc.configurable, true, 'view should be configurable');
assert_not_equals(viewPropDesc.get, undefined, 'view should have a getter');
assert_equals(viewPropDesc.set, undefined, 'view should not have a setter');
assert_equals(byobReq.constructor.length, 2, 'constructor has 2 parameters');
assert_equals(byobReq.respond.length, 1, 'respond has 1 parameter');
assert_equals(byobReq.respondWithNewView.length, 1, 'respondWithNewView has 1 parameter');
}, 'ReadableStreamBYOBRequest instances should have the correct list of properties');
test(function() {
let controller;
const rs = new ReadableStream({
start: function(c) {
controller = c;
},
type: "bytes"
});
assert_equals(controller.byobRequest, undefined, "by default byobRequest should be undefined");
}, "By default, byobRequest should be undefined");
test(function() {
let controller;
const autoAllocateChunkSize = 128;
const rs = new ReadableStream({
autoAllocateChunkSize,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_equals(byobReq.view.length, autoAllocateChunkSize, "byobRequest length should be equal to autoAllocateChunkSize value")
}, "byobRequest.view length should be equal to autoAllocateChunkSize")
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_throws(new TypeError("Can only call ReadableStreamBYOBRequest.respond on instances of ReadableStreamBYOBRequest"),
function() { byobReq.respond.apply(rs, 1); });
}, "Calling respond() with a this object different from ReadableStreamBYOBRequest should throw a TypeError");
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_throws(new RangeError("bytesWritten has an incorrect value"),
function() { byobReq.respond(-1); });
}, "Calling respond() with a negative bytesWritten value should throw a RangeError");
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_throws(new RangeError("bytesWritten has an incorrect value"),
function() { byobReq.respond("abc"); });
}, "Calling respond() with a bytesWritten value which is not a number should throw a RangeError");
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_throws(new RangeError("bytesWritten has an incorrect value"),
function() { byobReq.respond(Number.POSITIVE_INFINITY); });
}, "Calling respond() with a positive infinity bytesWritten value should throw a RangeError");
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
controller.close();
assert_throws(new TypeError("bytesWritten is different from 0 even though stream is closed"),
function() { byobReq.respond(1); });
}, "Calling respond() with a bytesWritten value different from 0 when stream is closed should throw a TypeError");
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
// FIXME: When ReadableStreamBYOBReader is implemented, another test (or even several ones)
// based on this one should be added so that reader's readIntoRequests attribute is not empty
// and currently unreachable code is reached.
rs.getReader().read();
const byobReq = controller.byobRequest;
controller.close();
byobReq.respond(0);
}, "Calling respond() with a bytesWritten value of 0 when stream is closed should succeed");
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_throws(new RangeError("bytesWritten value is too great"),
function() { byobReq.respond(17); });
}, "Calling respond() with a bytesWritten value greater than autoAllocateChunkSize should fail");
promise_test(function() {
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
pull: function(controller) {
const br = controller.byobRequest;
br.view[0] = 1;
br.view[1] = 2;
br.respond(2);
},
type: "bytes"
});
return rs.getReader().read().then(result => {
assert_equals(result.value.byteLength, 2);
assert_equals(result.value.byteOffset, 0);
assert_equals(result.value.buffer.byteLength, 16);
assert_equals(result.value[0], 1);
assert_equals(result.value[1], 2);
});
}, "Calling respond() with a bytesWritten value lower than autoAllocateChunkSize should succeed");
// FIXME: when ReadableStreamBYOBReader is implemented, add tests with elementSize different from 1
// so that more code can be covered.
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_throws(new TypeError("Can only call ReadableStreamBYOBRequest.respondWithNewView on instances of ReadableStreamBYOBRequest"),
function() { byobReq.respondWithNewView.apply(rs, new Uint8Array(1)); });
}, "Calling respondWithNewView() with a this object different from ReadableStreamBYOBRequest should throw a TypeError");
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_throws(new TypeError("Provided view is not an object"),
function() { byobReq.respondWithNewView(function() {}); });
}, "Calling respondWithNewView() with an argument that is not an object should throw a TypeError");
test(function() {
let controller;
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
start: function(c) {
controller = c;
},
type: "bytes"
});
rs.getReader().read();
const byobReq = controller.byobRequest;
assert_throws(new TypeError("Provided view is not an ArrayBufferView"),
function() { byobReq.respondWithNewView({}); });
}, "Calling respondWithNewView() with an argument that is not an ArrayBufferView should throw a TypeError");
promise_test(function() {
const rs = new ReadableStream({
autoAllocateChunkSize: 2,
pull: function(controller) {
const newView = new Uint8Array([3, 6]);
const br = controller.byobRequest;
br.respondWithNewView(newView);
},
type: "bytes"
});
return rs.getReader().read().then(result => {
assert_equals(result.value.byteLength, 2);
assert_equals(result.value.byteOffset, 0);
assert_equals(result.value.buffer.byteLength, 2);
assert_equals(result.value[0], 3);
assert_equals(result.value[1], 6);
});
}, "When using autoAllocateChunkSize, calling respondWithNewView() should succeed if view.byteLength is equal to autoAllocateChunkSize");
promise_test(function(test) {
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
pull: function(controller) {
const newView = new Uint8Array([3, 6]);
const br = controller.byobRequest;
br.respondWithNewView(newView);
},
type: "bytes"
});
const error = new RangeError("Invalid value for view.byteLength");
return promise_rejects(test, error, rs.getReader().read());
}, "When using autoAllocateChunkSize, calling respondWithNewView() should throw a RangeError if view.byteOffset is different from 0");
promise_test(function(test) {
const rs = new ReadableStream({
autoAllocateChunkSize: 16,
pull: function(controller) {
const buffer = new ArrayBuffer(3);
const newView = new Uint8Array(buffer, 1); // byteOffset of 1
const br = controller.byobRequest;
br.respondWithNewView(newView);
},
type: "bytes"
});
const error = new RangeError("Invalid value for view.byteOffset");
return promise_rejects(test, error, rs.getReader().read());
}, "When using autoAllocateChunkSize, calling respondWithNewView() should throw a RangeError if view.byteLength is different from autoAllocateChunkSize");
done();