tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

write.any.js (10017B)


      1 // META: global=window,worker,shadowrealm
      2 // META: script=../resources/test-utils.js
      3 // META: script=../resources/recording-streams.js
      4 'use strict';
      5 
      6 const error1 = new Error('error1');
      7 error1.name = 'error1';
      8 
      9 const error2 = new Error('error2');
     10 error2.name = 'error2';
     11 
     12 function writeArrayToStream(array, writableStreamWriter) {
     13  array.forEach(chunk => writableStreamWriter.write(chunk));
     14  return writableStreamWriter.close();
     15 }
     16 
     17 promise_test(() => {
     18  let storage;
     19  const ws = new WritableStream({
     20    start() {
     21      storage = [];
     22    },
     23 
     24    write(chunk) {
     25      return delay(0).then(() => storage.push(chunk));
     26    },
     27 
     28    close() {
     29      return delay(0);
     30    }
     31  });
     32 
     33  const writer = ws.getWriter();
     34 
     35  const input = [1, 2, 3, 4, 5];
     36  return writeArrayToStream(input, writer)
     37      .then(() => assert_array_equals(storage, input, 'correct data should be relayed to underlying sink'));
     38 }, 'WritableStream should complete asynchronous writes before close resolves');
     39 
     40 promise_test(() => {
     41  const ws = recordingWritableStream();
     42 
     43  const writer = ws.getWriter();
     44 
     45  const input = [1, 2, 3, 4, 5];
     46  return writeArrayToStream(input, writer)
     47      .then(() => assert_array_equals(ws.events, ['write', 1, 'write', 2, 'write', 3, 'write', 4, 'write', 5, 'close'],
     48                                      'correct data should be relayed to underlying sink'));
     49 }, 'WritableStream should complete synchronous writes before close resolves');
     50 
     51 promise_test(() => {
     52  const ws = new WritableStream({
     53    write() {
     54      return 'Hello';
     55    }
     56  });
     57 
     58  const writer = ws.getWriter();
     59 
     60  const writePromise = writer.write('a');
     61  return writePromise
     62      .then(value => assert_equals(value, undefined, 'fulfillment value must be undefined'));
     63 }, 'fulfillment value of ws.write() call should be undefined even if the underlying sink returns a non-undefined ' +
     64    'value');
     65 
     66 promise_test(() => {
     67  let resolveSinkWritePromise;
     68  const ws = new WritableStream({
     69    write() {
     70      return new Promise(resolve => {
     71        resolveSinkWritePromise = resolve;
     72      });
     73    }
     74  });
     75 
     76  const writer = ws.getWriter();
     77 
     78  assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
     79 
     80  return writer.ready.then(() => {
     81    const writePromise = writer.write('a');
     82    let writePromiseResolved = false;
     83    assert_not_equals(resolveSinkWritePromise, undefined, 'resolveSinkWritePromise should not be undefined');
     84 
     85    assert_equals(writer.desiredSize, 0, 'desiredSize should be 0 after writer.write()');
     86 
     87    return Promise.all([
     88      writePromise.then(value => {
     89        writePromiseResolved = true;
     90        assert_equals(resolveSinkWritePromise, undefined, 'sinkWritePromise should be fulfilled before writePromise');
     91 
     92        assert_equals(value, undefined, 'writePromise should be fulfilled with undefined');
     93      }),
     94      writer.ready.then(value => {
     95        assert_equals(resolveSinkWritePromise, undefined, 'sinkWritePromise should be fulfilled before writer.ready');
     96        assert_true(writePromiseResolved, 'writePromise should be fulfilled before writer.ready');
     97 
     98        assert_equals(writer.desiredSize, 1, 'desiredSize should be 1 again');
     99 
    100        assert_equals(value, undefined, 'writePromise should be fulfilled with undefined');
    101      }),
    102      flushAsyncEvents().then(() => {
    103        resolveSinkWritePromise();
    104        resolveSinkWritePromise = undefined;
    105      })
    106    ]);
    107  });
    108 }, 'WritableStream should transition to waiting until write is acknowledged');
    109 
    110 promise_test(t => {
    111  let sinkWritePromiseRejectors = [];
    112  const ws = new WritableStream({
    113    write() {
    114      const sinkWritePromise = new Promise((r, reject) => sinkWritePromiseRejectors.push(reject));
    115      return sinkWritePromise;
    116    }
    117  });
    118 
    119  const writer = ws.getWriter();
    120 
    121  assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
    122 
    123  return writer.ready.then(() => {
    124    const writePromise = writer.write('a');
    125    assert_equals(sinkWritePromiseRejectors.length, 1, 'there should be 1 rejector');
    126    assert_equals(writer.desiredSize, 0, 'desiredSize should be 0');
    127 
    128    const writePromise2 = writer.write('b');
    129    assert_equals(sinkWritePromiseRejectors.length, 1, 'there should be still 1 rejector');
    130    assert_equals(writer.desiredSize, -1, 'desiredSize should be -1');
    131 
    132    const closedPromise = writer.close();
    133 
    134    assert_equals(writer.desiredSize, -1, 'desiredSize should still be -1');
    135 
    136    return Promise.all([
    137      promise_rejects_exactly(t, error1, closedPromise,
    138                              'closedPromise should reject with the error returned from the sink\'s write method')
    139          .then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
    140                                    'sinkWritePromise should reject before closedPromise')),
    141      promise_rejects_exactly(t, error1, writePromise,
    142                              'writePromise should reject with the error returned from the sink\'s write method')
    143          .then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
    144                                    'sinkWritePromise should reject before writePromise')),
    145      promise_rejects_exactly(t, error1, writePromise2,
    146                              'writePromise2 should reject with the error returned from the sink\'s write method')
    147          .then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
    148                                    'sinkWritePromise should reject before writePromise2')),
    149      flushAsyncEvents().then(() => {
    150        sinkWritePromiseRejectors[0](error1);
    151        sinkWritePromiseRejectors = [];
    152      })
    153    ]);
    154  });
    155 }, 'when write returns a rejected promise, queued writes and close should be cleared');
    156 
    157 promise_test(t => {
    158  const ws = new WritableStream({
    159    write() {
    160      throw error1;
    161    }
    162  });
    163 
    164  const writer = ws.getWriter();
    165 
    166  return promise_rejects_exactly(t, error1, writer.write('a'),
    167                                 'write() should reject with the error returned from the sink\'s write method')
    168      .then(() => promise_rejects_js(t, TypeError, writer.close(), 'close() should be rejected'));
    169 }, 'when sink\'s write throws an error, the stream should become errored and the promise should reject');
    170 
    171 promise_test(t => {
    172  const ws = new WritableStream({
    173    write(chunk, controller) {
    174      controller.error(error1);
    175      throw error2;
    176    }
    177  });
    178 
    179  const writer = ws.getWriter();
    180 
    181  return promise_rejects_exactly(t, error2, writer.write('a'),
    182                                 'write() should reject with the error returned from the sink\'s write method ')
    183  .then(() => {
    184    return Promise.all([
    185      promise_rejects_exactly(t, error1, writer.ready,
    186                              'writer.ready must reject with the error passed to the controller'),
    187      promise_rejects_exactly(t, error1, writer.closed,
    188                              'writer.closed must reject with the error passed to the controller')
    189    ]);
    190  });
    191 }, 'writer.write(), ready and closed reject with the error passed to controller.error() made before sink.write' +
    192    ' rejection');
    193 
    194 promise_test(() => {
    195  const numberOfWrites = 1000;
    196 
    197  let resolveFirstWritePromise;
    198  let writeCount = 0;
    199  const ws = new WritableStream({
    200    write() {
    201      ++writeCount;
    202      if (!resolveFirstWritePromise) {
    203        return new Promise(resolve => {
    204          resolveFirstWritePromise = resolve;
    205        });
    206      }
    207      return Promise.resolve();
    208    }
    209  });
    210 
    211  const writer = ws.getWriter();
    212  return writer.ready.then(() => {
    213    for (let i = 1; i < numberOfWrites; ++i) {
    214      writer.write('a');
    215    }
    216    const writePromise = writer.write('a');
    217 
    218    assert_equals(writeCount, 1, 'should have called sink\'s write once');
    219 
    220    resolveFirstWritePromise();
    221 
    222    return writePromise
    223        .then(() =>
    224        assert_equals(writeCount, numberOfWrites, `should have called sink's write ${numberOfWrites} times`));
    225  });
    226 }, 'a large queue of writes should be processed completely');
    227 
    228 promise_test(() => {
    229  const stream = recordingWritableStream();
    230  const w = stream.getWriter();
    231  const WritableStreamDefaultWriter = w.constructor;
    232  w.releaseLock();
    233  const writer = new WritableStreamDefaultWriter(stream);
    234  return writer.ready.then(() => {
    235    writer.write('a');
    236    assert_array_equals(stream.events, ['write', 'a'], 'write() should be passed to sink');
    237  });
    238 }, 'WritableStreamDefaultWriter should work when manually constructed');
    239 
    240 promise_test(() => {
    241  let thenCalled = false;
    242  const ws = new WritableStream({
    243    write() {
    244      return {
    245        then(onFulfilled) {
    246          thenCalled = true;
    247          onFulfilled();
    248        }
    249      };
    250    }
    251  });
    252  return ws.getWriter().write('a').then(() => assert_true(thenCalled, 'thenCalled should be true'));
    253 }, 'returning a thenable from write() should work');
    254 
    255 promise_test(() => {
    256  const stream = new WritableStream();
    257  const writer = stream.getWriter();
    258  const WritableStreamDefaultWriter = writer.constructor;
    259  assert_throws_js(TypeError, () => new WritableStreamDefaultWriter(stream),
    260                   'should not be able to construct on locked stream');
    261  // If stream.[[writer]] no longer points to |writer| then the closed Promise
    262  // won't work properly.
    263  return Promise.all([writer.close(), writer.closed]);
    264 }, 'failing DefaultWriter constructor should not release an existing writer');
    265 
    266 promise_test(t => {
    267  const ws = new WritableStream({
    268    start() {
    269      return Promise.reject(error1);
    270    }
    271  }, { highWaterMark: 0 });
    272  const writer = ws.getWriter();
    273  return Promise.all([
    274    promise_rejects_exactly(t, error1, writer.ready, 'ready should be rejected'),
    275    promise_rejects_exactly(t, error1, writer.write(), 'write() should be rejected')
    276  ]);
    277 }, 'write() on a stream with HWM 0 should not cause the ready Promise to resolve');
    278 
    279 promise_test(t => {
    280  const ws = new WritableStream();
    281  const writer = ws.getWriter();
    282  writer.releaseLock();
    283  return promise_rejects_js(t, TypeError, writer.write(), 'write should reject');
    284 }, 'writing to a released writer should reject the returned promise');