mirror of
https://github.com/servo/servo.git
synced 2025-06-23 08:34:42 +01:00
258 lines
8.5 KiB
JavaScript
258 lines
8.5 KiB
JavaScript
'use strict';
|
|
|
|
if (self.importScripts) {
|
|
self.importScripts('/resources/testharness.js');
|
|
self.importScripts('../resources/test-utils.js');
|
|
self.importScripts('../resources/recording-streams.js');
|
|
}
|
|
|
|
const error1 = new Error('error1');
|
|
error1.name = 'error1';
|
|
|
|
const error2 = new Error('error2');
|
|
error2.name = 'error2';
|
|
|
|
function writeArrayToStream(array, writableStreamWriter) {
|
|
array.forEach(chunk => writableStreamWriter.write(chunk));
|
|
return writableStreamWriter.close();
|
|
}
|
|
|
|
promise_test(() => {
|
|
let storage;
|
|
const ws = new WritableStream({
|
|
start() {
|
|
storage = [];
|
|
},
|
|
|
|
write(chunk) {
|
|
return delay(0).then(() => storage.push(chunk));
|
|
},
|
|
|
|
close() {
|
|
return delay(0);
|
|
}
|
|
});
|
|
|
|
const writer = ws.getWriter();
|
|
|
|
const input = [1, 2, 3, 4, 5];
|
|
return writeArrayToStream(input, writer)
|
|
.then(() => assert_array_equals(storage, input, 'correct data should be relayed to underlying sink'));
|
|
}, 'WritableStream should complete asynchronous writes before close resolves');
|
|
|
|
promise_test(() => {
|
|
const ws = recordingWritableStream();
|
|
|
|
const writer = ws.getWriter();
|
|
|
|
const input = [1, 2, 3, 4, 5];
|
|
return writeArrayToStream(input, writer)
|
|
.then(() => assert_array_equals(ws.events, ['write', 1, 'write', 2, 'write', 3, 'write', 4, 'write', 5, 'close'],
|
|
'correct data should be relayed to underlying sink'));
|
|
}, 'WritableStream should complete synchronous writes before close resolves');
|
|
|
|
promise_test(() => {
|
|
const ws = new WritableStream({
|
|
write() {
|
|
return 'Hello';
|
|
}
|
|
});
|
|
|
|
const writer = ws.getWriter();
|
|
|
|
const writePromise = writer.write('a');
|
|
return writePromise
|
|
.then(value => assert_equals(value, undefined, 'fulfillment value must be undefined'));
|
|
}, 'fulfillment value of ws.write() call should be undefined even if the underlying sink returns a non-undefined ' +
|
|
'value');
|
|
|
|
promise_test(() => {
|
|
let resolveSinkWritePromise;
|
|
const ws = new WritableStream({
|
|
write() {
|
|
return new Promise(resolve => {
|
|
resolveSinkWritePromise = resolve;
|
|
});
|
|
}
|
|
});
|
|
|
|
const writer = ws.getWriter();
|
|
|
|
assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
|
|
|
|
return writer.ready.then(() => {
|
|
const writePromise = writer.write('a');
|
|
let writePromiseResolved = false;
|
|
assert_not_equals(resolveSinkWritePromise, undefined, 'resolveSinkWritePromise should not be undefined');
|
|
|
|
assert_equals(writer.desiredSize, 0, 'desiredSize should be 0 after writer.write()');
|
|
|
|
return Promise.all([
|
|
writePromise.then(value => {
|
|
writePromiseResolved = true;
|
|
assert_equals(resolveSinkWritePromise, undefined, 'sinkWritePromise should be fulfilled before writePromise');
|
|
|
|
assert_equals(value, undefined, 'writePromise should be fulfilled with undefined');
|
|
}),
|
|
writer.ready.then(value => {
|
|
assert_equals(resolveSinkWritePromise, undefined, 'sinkWritePromise should be fulfilled before writer.ready');
|
|
assert_true(writePromiseResolved, 'writePromise should be fulfilled before writer.ready');
|
|
|
|
assert_equals(writer.desiredSize, 1, 'desiredSize should be 1 again');
|
|
|
|
assert_equals(value, undefined, 'writePromise should be fulfilled with undefined');
|
|
}),
|
|
flushAsyncEvents().then(() => {
|
|
resolveSinkWritePromise();
|
|
resolveSinkWritePromise = undefined;
|
|
})
|
|
]);
|
|
});
|
|
}, 'WritableStream should transition to waiting until write is acknowledged');
|
|
|
|
promise_test(t => {
|
|
let sinkWritePromiseRejectors = [];
|
|
const ws = new WritableStream({
|
|
write() {
|
|
const sinkWritePromise = new Promise((r, reject) => sinkWritePromiseRejectors.push(reject));
|
|
return sinkWritePromise;
|
|
}
|
|
});
|
|
|
|
const writer = ws.getWriter();
|
|
|
|
assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
|
|
|
|
return writer.ready.then(() => {
|
|
const writePromise = writer.write('a');
|
|
assert_equals(sinkWritePromiseRejectors.length, 1, 'there should be 1 rejector');
|
|
assert_equals(writer.desiredSize, 0, 'desiredSize should be 0');
|
|
|
|
const writePromise2 = writer.write('b');
|
|
assert_equals(sinkWritePromiseRejectors.length, 1, 'there should be still 1 rejector');
|
|
assert_equals(writer.desiredSize, -1, 'desiredSize should be -1');
|
|
|
|
const closedPromise = writer.close();
|
|
|
|
assert_equals(writer.desiredSize, -1, 'desiredSize should still be -1');
|
|
|
|
return Promise.all([
|
|
promise_rejects(t, error1, closedPromise,
|
|
'closedPromise should reject with the error returned from the sink\'s write method')
|
|
.then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
|
|
'sinkWritePromise should reject before closedPromise')),
|
|
promise_rejects(t, error1, writePromise,
|
|
'writePromise should reject with the error returned from the sink\'s write method')
|
|
.then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
|
|
'sinkWritePromise should reject before writePromise')),
|
|
promise_rejects(t, error1, writePromise2,
|
|
'writePromise2 should reject with the error returned from the sink\'s write method')
|
|
.then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
|
|
'sinkWritePromise should reject before writePromise2')),
|
|
flushAsyncEvents().then(() => {
|
|
sinkWritePromiseRejectors[0](error1);
|
|
sinkWritePromiseRejectors = [];
|
|
})
|
|
]);
|
|
});
|
|
}, 'when write returns a rejected promise, queued writes and close should be cleared');
|
|
|
|
promise_test(t => {
|
|
const ws = new WritableStream({
|
|
write() {
|
|
throw error1;
|
|
}
|
|
});
|
|
|
|
const writer = ws.getWriter();
|
|
|
|
return promise_rejects(t, error1, writer.write('a'),
|
|
'write() should reject with the error returned from the sink\'s write method')
|
|
.then(() => promise_rejects(t, new TypeError(), writer.close(), 'close() should be rejected'));
|
|
}, 'when sink\'s write throws an error, the stream should become errored and the promise should reject');
|
|
|
|
promise_test(t => {
|
|
const ws = new WritableStream({
|
|
write(chunk, controller) {
|
|
controller.error(error1);
|
|
throw error2;
|
|
}
|
|
});
|
|
|
|
const writer = ws.getWriter();
|
|
|
|
return promise_rejects(t, error2, writer.write('a'),
|
|
'write() should reject with the error returned from the sink\'s write method ')
|
|
.then(() => {
|
|
return Promise.all([
|
|
promise_rejects(t, error1, writer.ready,
|
|
'writer.ready must reject with the error passed to the controller'),
|
|
promise_rejects(t, error1, writer.closed,
|
|
'writer.closed must reject with the error passed to the controller')
|
|
]);
|
|
});
|
|
}, 'writer.write(), ready and closed reject with the error passed to controller.error() made before sink.write' +
|
|
' rejection');
|
|
|
|
promise_test(() => {
|
|
const numberOfWrites = 1000;
|
|
|
|
let resolveFirstWritePromise;
|
|
let writeCount = 0;
|
|
const ws = new WritableStream({
|
|
write() {
|
|
++writeCount;
|
|
if (!resolveFirstWritePromise) {
|
|
return new Promise(resolve => {
|
|
resolveFirstWritePromise = resolve;
|
|
});
|
|
}
|
|
return Promise.resolve();
|
|
}
|
|
});
|
|
|
|
const writer = ws.getWriter();
|
|
return writer.ready.then(() => {
|
|
for (let i = 1; i < numberOfWrites; ++i) {
|
|
writer.write('a');
|
|
}
|
|
const writePromise = writer.write('a');
|
|
|
|
assert_equals(writeCount, 1, 'should have called sink\'s write once');
|
|
|
|
resolveFirstWritePromise();
|
|
|
|
return writePromise
|
|
.then(() =>
|
|
assert_equals(writeCount, numberOfWrites, `should have called sink's write ${numberOfWrites} times`));
|
|
});
|
|
}, 'a large queue of writes should be processed completely');
|
|
|
|
promise_test(() => {
|
|
const stream = recordingWritableStream();
|
|
const w = stream.getWriter();
|
|
const WritableStreamDefaultWriter = w.constructor;
|
|
w.releaseLock();
|
|
const writer = new WritableStreamDefaultWriter(stream);
|
|
return writer.ready.then(() => {
|
|
writer.write('a');
|
|
assert_array_equals(stream.events, ['write', 'a'], 'write() should be passed to sink');
|
|
});
|
|
}, 'WritableStreamDefaultWriter should work when manually constructed');
|
|
|
|
promise_test(() => {
|
|
let thenCalled = false;
|
|
const ws = new WritableStream({
|
|
write() {
|
|
return {
|
|
then(onFulfilled) {
|
|
thenCalled = true;
|
|
onFulfilled();
|
|
}
|
|
};
|
|
}
|
|
});
|
|
return ws.getWriter().write('a').then(() => assert_true(thenCalled, 'thenCalled should be true'));
|
|
}, 'returning a thenable from write() should work');
|
|
|
|
done();
|