tor-browser

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

reentrant-strategy.any.js (6193B)


      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 // These tests exercise the pathological case of calling WritableStream* methods from within the strategy.size()
      7 // callback. This is not something any real code should ever do. Failures here indicate subtle deviations from the
      8 // standard that may affect real, non-pathological code.
      9 
     10 const error1 = { name: 'error1' };
     11 
     12 promise_test(() => {
     13  let writer;
     14  const strategy = {
     15    size(chunk) {
     16      if (chunk > 0) {
     17        writer.write(chunk - 1);
     18      }
     19      return chunk;
     20    }
     21  };
     22 
     23  const ws = recordingWritableStream({}, strategy);
     24  writer = ws.getWriter();
     25  return writer.write(2)
     26      .then(() => {
     27        assert_array_equals(ws.events, ['write', 0, 'write', 1, 'write', 2], 'writes should appear in order');
     28      });
     29 }, 'writes should be written in the standard order');
     30 
     31 promise_test(() => {
     32  let writer;
     33  const events = [];
     34  const strategy = {
     35    size(chunk) {
     36      events.push('size', chunk);
     37      if (chunk > 0) {
     38        writer.write(chunk - 1)
     39            .then(() => events.push('writer.write done', chunk - 1));
     40      }
     41      return chunk;
     42    }
     43  };
     44  const ws = new WritableStream({
     45    write(chunk) {
     46      events.push('sink.write', chunk);
     47    }
     48  }, strategy);
     49  writer = ws.getWriter();
     50  return writer.write(2)
     51      .then(() => events.push('writer.write done', 2))
     52      .then(() => flushAsyncEvents())
     53      .then(() => {
     54        assert_array_equals(events, ['size', 2, 'size', 1, 'size', 0,
     55                                     'sink.write', 0, 'sink.write', 1, 'writer.write done', 0,
     56                                     'sink.write', 2, 'writer.write done', 1,
     57                                     'writer.write done', 2],
     58                            'events should happen in standard order');
     59      });
     60 }, 'writer.write() promises should resolve in the standard order');
     61 
     62 promise_test(t => {
     63  let controller;
     64  const strategy = {
     65    size() {
     66      controller.error(error1);
     67      return 1;
     68    }
     69  };
     70  const ws = recordingWritableStream({
     71    start(c) {
     72      controller = c;
     73    }
     74  }, strategy);
     75  const resolved = [];
     76  const writer = ws.getWriter();
     77  const readyPromise1 = writer.ready.then(() => resolved.push('ready1'));
     78  const writePromise = promise_rejects_exactly(t, error1, writer.write(),
     79                                               'write() should reject with the error')
     80                                                   .then(() => resolved.push('write'));
     81  const readyPromise2 = promise_rejects_exactly(t, error1, writer.ready, 'ready should reject with error1')
     82      .then(() => resolved.push('ready2'));
     83  const closedPromise = promise_rejects_exactly(t, error1, writer.closed, 'closed should reject with error1')
     84      .then(() => resolved.push('closed'));
     85  return Promise.all([readyPromise1, writePromise, readyPromise2, closedPromise])
     86      .then(() => {
     87        assert_array_equals(resolved, ['ready1', 'write', 'ready2', 'closed'],
     88                            'promises should resolve in standard order');
     89        assert_array_equals(ws.events, [], 'underlying sink write should not be called');
     90      });
     91 }, 'controller.error() should work when called from within strategy.size()');
     92 
     93 promise_test(t => {
     94  let writer;
     95  const strategy = {
     96    size() {
     97      writer.close();
     98      return 1;
     99    }
    100  };
    101 
    102  const ws = recordingWritableStream({}, strategy);
    103  writer = ws.getWriter();
    104  return promise_rejects_js(t, TypeError, writer.write('a'), 'write() promise should reject')
    105      .then(() => {
    106        assert_array_equals(ws.events, ['close'], 'sink.write() should not be called');
    107      });
    108 }, 'close() should work when called from within strategy.size()');
    109 
    110 promise_test(t => {
    111  let writer;
    112  const strategy = {
    113    size() {
    114      writer.abort(error1);
    115      return 1;
    116    }
    117  };
    118 
    119  const ws = recordingWritableStream({}, strategy);
    120  writer = ws.getWriter();
    121  return promise_rejects_exactly(t, error1, writer.write('a'), 'write() promise should reject')
    122      .then(() => {
    123        assert_array_equals(ws.events, ['abort', error1], 'sink.write() should not be called');
    124      });
    125 }, 'abort() should work when called from within strategy.size()');
    126 
    127 promise_test(t => {
    128  let writer;
    129  const strategy = {
    130    size() {
    131      writer.releaseLock();
    132      return 1;
    133    }
    134  };
    135 
    136  const ws = recordingWritableStream({}, strategy);
    137  writer = ws.getWriter();
    138  const writePromise = promise_rejects_js(t, TypeError, writer.write('a'), 'write() promise should reject');
    139  const readyPromise = promise_rejects_js(t, TypeError, writer.ready, 'ready promise should reject');
    140  const closedPromise = promise_rejects_js(t, TypeError, writer.closed, 'closed promise should reject');
    141  return Promise.all([writePromise, readyPromise, closedPromise])
    142      .then(() => {
    143        assert_array_equals(ws.events, [], 'sink.write() should not be called');
    144      });
    145 }, 'releaseLock() should abort the write() when called within strategy.size()');
    146 
    147 promise_test(t => {
    148  let writer1;
    149  let ws;
    150  let writePromise2;
    151  let closePromise;
    152  let closedPromise2;
    153  const strategy = {
    154    size(chunk) {
    155      if (chunk > 0) {
    156        writer1.releaseLock();
    157        const writer2 = ws.getWriter();
    158        writePromise2 = writer2.write(0);
    159        closePromise = writer2.close();
    160        closedPromise2 = writer2.closed;
    161      }
    162      return 1;
    163    }
    164  };
    165  ws = recordingWritableStream({}, strategy);
    166  writer1 = ws.getWriter();
    167  const writePromise1 = promise_rejects_js(t, TypeError, writer1.write(1), 'write() promise should reject');
    168  const readyPromise = promise_rejects_js(t, TypeError, writer1.ready, 'ready promise should reject');
    169  const closedPromise1 = promise_rejects_js(t, TypeError, writer1.closed, 'closed promise should reject');
    170  return Promise.all([writePromise1, readyPromise, closedPromise1, writePromise2, closePromise, closedPromise2])
    171      .then(() => {
    172        assert_array_equals(ws.events, ['write', 0, 'close'], 'sink.write() should only be called once');
    173      });
    174 }, 'original reader should error when new reader is created within strategy.size()');