tor-browser

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

general.any.js (24109B)


      1 // META: global=window,worker,shadowrealm
      2 // META: script=../resources/test-utils.js
      3 // META: script=../resources/rs-utils.js
      4 'use strict';
      5 
      6 const error1 = new Error('error1');
      7 error1.name = 'error1';
      8 
      9 test(() => {
     10 
     11  new ReadableStream(); // ReadableStream constructed with no parameters
     12  new ReadableStream({ }); // ReadableStream constructed with an empty object as parameter
     13  new ReadableStream({ type: undefined }); // ReadableStream constructed with undefined type
     14  new ReadableStream(undefined); // ReadableStream constructed with undefined as parameter
     15 
     16  let x;
     17  new ReadableStream(x); // ReadableStream constructed with an undefined variable as parameter
     18 
     19 }, 'ReadableStream can be constructed with no errors');
     20 
     21 test(() => {
     22 
     23  assert_throws_js(TypeError, () => new ReadableStream(null), 'constructor should throw when the source is null');
     24 
     25 }, 'ReadableStream can\'t be constructed with garbage');
     26 
     27 test(() => {
     28 
     29  assert_throws_js(TypeError, () => new ReadableStream({ type: null }),
     30    'constructor should throw when the type is null');
     31  assert_throws_js(TypeError, () => new ReadableStream({ type: '' }),
     32    'constructor should throw when the type is empty string');
     33  assert_throws_js(TypeError, () => new ReadableStream({ type: 'asdf' }),
     34    'constructor should throw when the type is asdf');
     35  assert_throws_exactly(
     36    error1,
     37    () => new ReadableStream({ type: { get toString() { throw error1; } } }),
     38    'constructor should throw when ToString() throws'
     39  );
     40  assert_throws_exactly(
     41    error1,
     42    () => new ReadableStream({ type: { toString() { throw error1; } } }),
     43    'constructor should throw when ToString() throws'
     44  );
     45 
     46 }, 'ReadableStream can\'t be constructed with an invalid type');
     47 
     48 test(() => {
     49 
     50  assert_throws_js(TypeError, () => {
     51    new ReadableStream({ start: 'potato' });
     52  }, 'constructor should throw when start is not a function');
     53 
     54 }, 'ReadableStream constructor should throw for non-function start arguments');
     55 
     56 test(() => {
     57 
     58  assert_throws_js(TypeError, () => new ReadableStream({ cancel: '2' }), 'constructor should throw');
     59 
     60 }, 'ReadableStream constructor will not tolerate initial garbage as cancel argument');
     61 
     62 test(() => {
     63 
     64  assert_throws_js(TypeError, () => new ReadableStream({ pull: { } }), 'constructor should throw');
     65 
     66 }, 'ReadableStream constructor will not tolerate initial garbage as pull argument');
     67 
     68 test(() => {
     69 
     70  let startCalled = false;
     71 
     72  const source = {
     73    start() {
     74      assert_equals(this, source, 'source is this during start');
     75      startCalled = true;
     76    }
     77  };
     78 
     79  new ReadableStream(source);
     80  assert_true(startCalled);
     81 
     82 }, 'ReadableStream start should be called with the proper thisArg');
     83 
     84 test(() => {
     85 
     86  let startCalled = false;
     87  const source = {
     88    start(controller) {
     89      const properties = ['close', 'constructor', 'desiredSize', 'enqueue', 'error'];
     90      assert_array_equals(Object.getOwnPropertyNames(Object.getPrototypeOf(controller)).sort(), properties,
     91        'prototype should have the right properties');
     92 
     93      controller.test = '';
     94      assert_array_equals(Object.getOwnPropertyNames(Object.getPrototypeOf(controller)).sort(), properties,
     95        'prototype should still have the right properties');
     96      assert_not_equals(Object.getOwnPropertyNames(controller).indexOf('test'), -1,
     97        '"test" should be a property of the controller');
     98 
     99      startCalled = true;
    100    }
    101  };
    102 
    103  new ReadableStream(source);
    104  assert_true(startCalled);
    105 
    106 }, 'ReadableStream start controller parameter should be extensible');
    107 
    108 test(() => {
    109  (new ReadableStream()).getReader(undefined);
    110  (new ReadableStream()).getReader({});
    111  (new ReadableStream()).getReader({ mode: undefined, notmode: 'ignored' });
    112  assert_throws_js(TypeError, () => (new ReadableStream()).getReader({ mode: 'potato' }));
    113 }, 'default ReadableStream getReader() should only accept mode:undefined');
    114 
    115 promise_test(() => {
    116 
    117  function SimpleStreamSource() {}
    118  let resolve;
    119  const promise = new Promise(r => resolve = r);
    120  SimpleStreamSource.prototype = {
    121    start: resolve
    122  };
    123 
    124  new ReadableStream(new SimpleStreamSource());
    125  return promise;
    126 
    127 }, 'ReadableStream should be able to call start method within prototype chain of its source');
    128 
    129 promise_test(() => {
    130 
    131  const rs = new ReadableStream({
    132    start(c) {
    133      return delay(5).then(() => {
    134        c.enqueue('a');
    135        c.close();
    136      });
    137    }
    138  });
    139 
    140  const reader = rs.getReader();
    141  return reader.read().then(r => {
    142    assert_object_equals(r, { value: 'a', done: false }, 'value read should be the one enqueued');
    143    return reader.closed;
    144  });
    145 
    146 }, 'ReadableStream start should be able to return a promise');
    147 
    148 promise_test(() => {
    149 
    150  const theError = new Error('rejected!');
    151  const rs = new ReadableStream({
    152    start() {
    153      return delay(1).then(() => {
    154        throw theError;
    155      });
    156    }
    157  });
    158 
    159  return rs.getReader().closed.then(() => {
    160    assert_unreached('closed promise should be rejected');
    161  }, e => {
    162    assert_equals(e, theError, 'promise should be rejected with the same error');
    163  });
    164 
    165 }, 'ReadableStream start should be able to return a promise and reject it');
    166 
    167 promise_test(() => {
    168 
    169  const objects = [
    170    { potato: 'Give me more!' },
    171    'test',
    172    1
    173  ];
    174 
    175  const rs = new ReadableStream({
    176    start(c) {
    177      for (const o of objects) {
    178        c.enqueue(o);
    179      }
    180      c.close();
    181    }
    182  });
    183 
    184  const reader = rs.getReader();
    185 
    186  return Promise.all([reader.read(), reader.read(), reader.read(), reader.closed]).then(r => {
    187    assert_object_equals(r[0], { value: objects[0], done: false }, 'value read should be the one enqueued');
    188    assert_object_equals(r[1], { value: objects[1], done: false }, 'value read should be the one enqueued');
    189    assert_object_equals(r[2], { value: objects[2], done: false }, 'value read should be the one enqueued');
    190  });
    191 
    192 }, 'ReadableStream should be able to enqueue different objects.');
    193 
    194 promise_test(() => {
    195 
    196  const error = new Error('pull failure');
    197  const rs = new ReadableStream({
    198    pull() {
    199      return Promise.reject(error);
    200    }
    201  });
    202 
    203  const reader = rs.getReader();
    204 
    205  let closed = false;
    206  let read = false;
    207 
    208  return Promise.all([
    209    reader.closed.then(() => {
    210      assert_unreached('closed should be rejected');
    211    }, e => {
    212      closed = true;
    213      assert_false(read);
    214      assert_equals(e, error, 'closed should be rejected with the thrown error');
    215    }),
    216    reader.read().then(() => {
    217      assert_unreached('read() should be rejected');
    218    }, e => {
    219      read = true;
    220      assert_true(closed);
    221      assert_equals(e, error, 'read() should be rejected with the thrown error');
    222    })
    223  ]);
    224 
    225 }, 'ReadableStream: if pull rejects, it should error the stream');
    226 
    227 promise_test(() => {
    228 
    229  let pullCount = 0;
    230 
    231  new ReadableStream({
    232    pull() {
    233      pullCount++;
    234    }
    235  });
    236 
    237  return flushAsyncEvents().then(() => {
    238    assert_equals(pullCount, 1, 'pull should be called once start finishes');
    239    return delay(10);
    240  }).then(() => {
    241    assert_equals(pullCount, 1, 'pull should be called exactly once');
    242  });
    243 
    244 }, 'ReadableStream: should only call pull once upon starting the stream');
    245 
    246 promise_test(() => {
    247 
    248  let pullCount = 0;
    249 
    250  const rs = new ReadableStream({
    251    pull(c) {
    252      // Don't enqueue immediately after start. We want the stream to be empty when we call .read() on it.
    253      if (pullCount > 0) {
    254        c.enqueue(pullCount);
    255      }
    256      ++pullCount;
    257    }
    258  });
    259 
    260  return flushAsyncEvents().then(() => {
    261    assert_equals(pullCount, 1, 'pull should be called once start finishes');
    262  }).then(() => {
    263    const reader = rs.getReader();
    264    const read = reader.read();
    265    assert_equals(pullCount, 2, 'pull should be called when read is called');
    266    return read;
    267  }).then(result => {
    268    assert_equals(pullCount, 3, 'pull should be called again in reaction to calling read');
    269    assert_object_equals(result, { value: 1, done: false }, 'the result read should be the one enqueued');
    270  });
    271 
    272 }, 'ReadableStream: should call pull when trying to read from a started, empty stream');
    273 
    274 promise_test(() => {
    275 
    276  let pullCount = 0;
    277 
    278  const rs = new ReadableStream({
    279    start(c) {
    280      c.enqueue('a');
    281    },
    282    pull() {
    283      pullCount++;
    284    }
    285  });
    286 
    287  const read = rs.getReader().read();
    288  assert_equals(pullCount, 0, 'calling read() should not cause pull to be called yet');
    289 
    290  return flushAsyncEvents().then(() => {
    291    assert_equals(pullCount, 1, 'pull should be called once start finishes');
    292    return read;
    293  }).then(r => {
    294    assert_object_equals(r, { value: 'a', done: false }, 'first read() should return first chunk');
    295    assert_equals(pullCount, 1, 'pull should not have been called again');
    296    return delay(10);
    297  }).then(() => {
    298    assert_equals(pullCount, 1, 'pull should be called exactly once');
    299  });
    300 
    301 }, 'ReadableStream: should only call pull once on a non-empty stream read from before start fulfills');
    302 
    303 promise_test(() => {
    304 
    305  let pullCount = 0;
    306  const startPromise = Promise.resolve();
    307 
    308  const rs = new ReadableStream({
    309    start(c) {
    310      c.enqueue('a');
    311    },
    312    pull() {
    313      pullCount++;
    314    }
    315  });
    316 
    317  return flushAsyncEvents().then(() => {
    318    assert_equals(pullCount, 0, 'pull should not be called once start finishes, since the queue is full');
    319 
    320    const read = rs.getReader().read();
    321    assert_equals(pullCount, 1, 'calling read() should cause pull to be called immediately');
    322    return read;
    323  }).then(r => {
    324    assert_object_equals(r, { value: 'a', done: false }, 'first read() should return first chunk');
    325    return delay(10);
    326  }).then(() => {
    327    assert_equals(pullCount, 1, 'pull should be called exactly once');
    328  });
    329 
    330 }, 'ReadableStream: should only call pull once on a non-empty stream read from after start fulfills');
    331 
    332 promise_test(() => {
    333 
    334  let pullCount = 0;
    335  let controller;
    336 
    337  const rs = new ReadableStream({
    338    start(c) {
    339      controller = c;
    340    },
    341    pull() {
    342      ++pullCount;
    343    }
    344  });
    345 
    346  const reader = rs.getReader();
    347  return flushAsyncEvents().then(() => {
    348    assert_equals(pullCount, 1, 'pull should have been called once by the time the stream starts');
    349 
    350    controller.enqueue('a');
    351    assert_equals(pullCount, 1, 'pull should not have been called again after enqueue');
    352 
    353    return reader.read();
    354  }).then(() => {
    355    assert_equals(pullCount, 2, 'pull should have been called again after read');
    356 
    357    return delay(10);
    358  }).then(() => {
    359    assert_equals(pullCount, 2, 'pull should be called exactly twice');
    360  });
    361 }, 'ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining');
    362 
    363 promise_test(() => {
    364 
    365  let pullCount = 0;
    366  let controller;
    367 
    368  const rs = new ReadableStream({
    369    start(c) {
    370      controller = c;
    371    },
    372    pull() {
    373      ++pullCount;
    374    }
    375  });
    376 
    377  const reader = rs.getReader();
    378 
    379  return flushAsyncEvents().then(() => {
    380    assert_equals(pullCount, 1, 'pull should have been called once by the time the stream starts');
    381 
    382    controller.enqueue('a');
    383    assert_equals(pullCount, 1, 'pull should not have been called again after enqueue');
    384 
    385    controller.close();
    386 
    387    return reader.read();
    388  }).then(() => {
    389    assert_equals(pullCount, 1, 'pull should not have been called a second time after read');
    390 
    391    return delay(10);
    392  }).then(() => {
    393    assert_equals(pullCount, 1, 'pull should be called exactly once');
    394  });
    395 
    396 }, 'ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining');
    397 
    398 promise_test(() => {
    399 
    400  let resolve;
    401  let returnedPromise;
    402  let timesCalled = 0;
    403 
    404  const rs = new ReadableStream({
    405    pull(c) {
    406      c.enqueue(++timesCalled);
    407      returnedPromise = new Promise(r => resolve = r);
    408      return returnedPromise;
    409    }
    410  });
    411  const reader = rs.getReader();
    412 
    413  return reader.read()
    414  .then(result1 => {
    415    assert_equals(timesCalled, 1,
    416      'pull should have been called once after start, but not yet have been called a second time');
    417    assert_object_equals(result1, { value: 1, done: false }, 'read() should fulfill with the enqueued value');
    418 
    419    return delay(10);
    420  }).then(() => {
    421    assert_equals(timesCalled, 1, 'after 10 ms, pull should still only have been called once');
    422 
    423    resolve();
    424    return returnedPromise;
    425  }).then(() => {
    426    assert_equals(timesCalled, 2,
    427      'after the promise returned by pull is fulfilled, pull should be called a second time');
    428  });
    429 
    430 }, 'ReadableStream: should not call pull until the previous pull call\'s promise fulfills');
    431 
    432 promise_test(() => {
    433 
    434  let timesCalled = 0;
    435 
    436  const rs = new ReadableStream(
    437    {
    438      start(c) {
    439        c.enqueue('a');
    440        c.enqueue('b');
    441        c.enqueue('c');
    442      },
    443      pull() {
    444        ++timesCalled;
    445      }
    446    },
    447    {
    448      size() {
    449        return 1;
    450      },
    451      highWaterMark: Infinity
    452    }
    453  );
    454  const reader = rs.getReader();
    455 
    456  return flushAsyncEvents().then(() => {
    457    return reader.read();
    458  }).then(result1 => {
    459    assert_object_equals(result1, { value: 'a', done: false }, 'first chunk should be as expected');
    460 
    461    return reader.read();
    462  }).then(result2 => {
    463    assert_object_equals(result2, { value: 'b', done: false }, 'second chunk should be as expected');
    464 
    465    return reader.read();
    466  }).then(result3 => {
    467    assert_object_equals(result3, { value: 'c', done: false }, 'third chunk should be as expected');
    468 
    469    return delay(10);
    470  }).then(() => {
    471    // Once for after start, and once for every read.
    472    assert_equals(timesCalled, 4, 'pull() should be called exactly four times');
    473  });
    474 
    475 }, 'ReadableStream: should pull after start, and after every read');
    476 
    477 promise_test(() => {
    478 
    479  let timesCalled = 0;
    480  const startPromise = Promise.resolve();
    481 
    482  const rs = new ReadableStream({
    483    start(c) {
    484      c.enqueue('a');
    485      c.close();
    486      return startPromise;
    487    },
    488    pull() {
    489      ++timesCalled;
    490    }
    491  });
    492 
    493  const reader = rs.getReader();
    494  return startPromise.then(() => {
    495    assert_equals(timesCalled, 0, 'after start finishes, pull should not have been called');
    496 
    497    return reader.read();
    498  }).then(() => {
    499    assert_equals(timesCalled, 0, 'reading should not have triggered a pull call');
    500 
    501    return reader.closed;
    502  }).then(() => {
    503    assert_equals(timesCalled, 0, 'stream should have closed with still no calls to pull');
    504  });
    505 
    506 }, 'ReadableStream: should not call pull after start if the stream is now closed');
    507 
    508 promise_test(() => {
    509 
    510  let timesCalled = 0;
    511  let resolve;
    512  const ready = new Promise(r => resolve = r);
    513 
    514  new ReadableStream(
    515    {
    516      start() {},
    517      pull(c) {
    518        c.enqueue(++timesCalled);
    519 
    520        if (timesCalled === 4) {
    521          resolve();
    522        }
    523      }
    524    },
    525    {
    526      size() {
    527        return 1;
    528      },
    529      highWaterMark: 4
    530    }
    531  );
    532 
    533  return ready.then(() => {
    534    // after start: size = 0, pull()
    535    // after enqueue(1): size = 1, pull()
    536    // after enqueue(2): size = 2, pull()
    537    // after enqueue(3): size = 3, pull()
    538    // after enqueue(4): size = 4, do not pull
    539    assert_equals(timesCalled, 4, 'pull() should have been called four times');
    540  });
    541 
    542 }, 'ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows');
    543 
    544 promise_test(() => {
    545 
    546  let pullCalled = false;
    547 
    548  const rs = new ReadableStream({
    549    pull(c) {
    550      pullCalled = true;
    551      c.close();
    552    }
    553  });
    554 
    555  const reader = rs.getReader();
    556  return reader.closed.then(() => {
    557    assert_true(pullCalled);
    558  });
    559 
    560 }, 'ReadableStream pull should be able to close a stream.');
    561 
    562 promise_test(t => {
    563 
    564  const controllerError = { name: 'controller error' };
    565 
    566  const rs = new ReadableStream({
    567    pull(c) {
    568      c.error(controllerError);
    569    }
    570  });
    571 
    572  return promise_rejects_exactly(t, controllerError, rs.getReader().closed);
    573 
    574 }, 'ReadableStream pull should be able to error a stream.');
    575 
    576 promise_test(t => {
    577 
    578  const controllerError = { name: 'controller error' };
    579  const thrownError = { name: 'thrown error' };
    580 
    581  const rs = new ReadableStream({
    582    pull(c) {
    583      c.error(controllerError);
    584      throw thrownError;
    585    }
    586  });
    587 
    588  return promise_rejects_exactly(t, controllerError, rs.getReader().closed);
    589 
    590 }, 'ReadableStream pull should be able to error a stream and throw.');
    591 
    592 test(() => {
    593 
    594  let startCalled = false;
    595 
    596  new ReadableStream({
    597    start(c) {
    598      assert_equals(c.enqueue('a'), undefined, 'the first enqueue should return undefined');
    599      c.close();
    600 
    601      assert_throws_js(TypeError, () => c.enqueue('b'), 'enqueue after close should throw a TypeError');
    602      startCalled = true;
    603    }
    604  });
    605 
    606  assert_true(startCalled);
    607 
    608 }, 'ReadableStream: enqueue should throw when the stream is readable but draining');
    609 
    610 test(() => {
    611 
    612  let startCalled = false;
    613 
    614  new ReadableStream({
    615    start(c) {
    616      c.close();
    617 
    618      assert_throws_js(TypeError, () => c.enqueue('a'), 'enqueue after close should throw a TypeError');
    619      startCalled = true;
    620    }
    621  });
    622 
    623  assert_true(startCalled);
    624 
    625 }, 'ReadableStream: enqueue should throw when the stream is closed');
    626 
    627 promise_test(() => {
    628 
    629  let startCalled = 0;
    630  let pullCalled = 0;
    631  let cancelCalled = 0;
    632 
    633  /* eslint-disable no-use-before-define */
    634  class Source {
    635    start(c) {
    636      startCalled++;
    637      assert_equals(this, theSource, 'start() should be called with the correct this');
    638      c.enqueue('a');
    639    }
    640 
    641    pull() {
    642      pullCalled++;
    643      assert_equals(this, theSource, 'pull() should be called with the correct this');
    644    }
    645 
    646    cancel() {
    647      cancelCalled++;
    648      assert_equals(this, theSource, 'cancel() should be called with the correct this');
    649    }
    650  }
    651  /* eslint-enable no-use-before-define */
    652 
    653  const theSource = new Source();
    654  theSource.debugName = 'the source object passed to the constructor'; // makes test failures easier to diagnose
    655 
    656  const rs = new ReadableStream(theSource);
    657  const reader = rs.getReader();
    658 
    659  return reader.read().then(() => {
    660    reader.releaseLock();
    661    rs.cancel();
    662    assert_equals(startCalled, 1);
    663    assert_equals(pullCalled, 1);
    664    assert_equals(cancelCalled, 1);
    665    return rs.getReader().closed;
    666  });
    667 
    668 }, 'ReadableStream: should call underlying source methods as methods');
    669 
    670 test(() => {
    671  new ReadableStream({
    672    start(c) {
    673      assert_equals(c.desiredSize, 10, 'desiredSize must start at highWaterMark');
    674      c.close();
    675      assert_equals(c.desiredSize, 0, 'after closing, desiredSize must be 0');
    676    }
    677  }, {
    678    highWaterMark: 10
    679  });
    680 }, 'ReadableStream: desiredSize when closed');
    681 
    682 test(() => {
    683  new ReadableStream({
    684    start(c) {
    685      assert_equals(c.desiredSize, 10, 'desiredSize must start at highWaterMark');
    686      c.error();
    687      assert_equals(c.desiredSize, null, 'after erroring, desiredSize must be null');
    688    }
    689  }, {
    690    highWaterMark: 10
    691  });
    692 }, 'ReadableStream: desiredSize when errored');
    693 
    694 test(() => {
    695  class Subclass extends ReadableStream {
    696    extraFunction() {
    697      return true;
    698    }
    699  }
    700  assert_equals(
    701      Object.getPrototypeOf(Subclass.prototype), ReadableStream.prototype,
    702      'Subclass.prototype\'s prototype should be ReadableStream.prototype');
    703  assert_equals(Object.getPrototypeOf(Subclass), ReadableStream,
    704                'Subclass\'s prototype should be ReadableStream');
    705  const sub = new Subclass();
    706  assert_true(sub instanceof ReadableStream,
    707              'Subclass object should be an instance of ReadableStream');
    708  assert_true(sub instanceof Subclass,
    709              'Subclass object should be an instance of Subclass');
    710  const lockedGetter = Object.getOwnPropertyDescriptor(
    711      ReadableStream.prototype, 'locked').get;
    712  assert_equals(lockedGetter.call(sub), sub.locked,
    713                'Subclass object should pass brand check');
    714  assert_true(sub.extraFunction(),
    715              'extraFunction() should be present on Subclass object');
    716 }, 'Subclassing ReadableStream should work');
    717 
    718 test(() => {
    719 
    720  let startCalled = false;
    721  new ReadableStream({
    722    start(c) {
    723      assert_equals(c.desiredSize, 1);
    724      c.enqueue('a');
    725      assert_equals(c.desiredSize, 0);
    726      c.enqueue('b');
    727      assert_equals(c.desiredSize, -1);
    728      c.enqueue('c');
    729      assert_equals(c.desiredSize, -2);
    730      c.enqueue('d');
    731      assert_equals(c.desiredSize, -3);
    732      c.enqueue('e');
    733      startCalled = true;
    734    }
    735  });
    736 
    737  assert_true(startCalled);
    738 
    739 }, 'ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue');
    740 
    741 promise_test(() => {
    742 
    743  let controller;
    744  const rs = new ReadableStream({
    745    start(c) {
    746      controller = c;
    747    }
    748  });
    749  const reader = rs.getReader();
    750 
    751  assert_equals(controller.desiredSize, 1, 'desiredSize should start at 1');
    752  controller.enqueue('a');
    753  assert_equals(controller.desiredSize, 0, 'desiredSize should decrease to 0 after first enqueue');
    754 
    755  return reader.read().then(result1 => {
    756    assert_object_equals(result1, { value: 'a', done: false }, 'first chunk read should be correct');
    757 
    758    assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the first read');
    759    controller.enqueue('b');
    760    assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the second enqueue');
    761 
    762    return reader.read();
    763  }).then(result2 => {
    764    assert_object_equals(result2, { value: 'b', done: false }, 'second chunk read should be correct');
    765 
    766    assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the second read');
    767    controller.enqueue('c');
    768    assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the third enqueue');
    769 
    770    return reader.read();
    771  }).then(result3 => {
    772    assert_object_equals(result3, { value: 'c', done: false }, 'third chunk read should be correct');
    773 
    774    assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the third read');
    775    controller.enqueue('d');
    776    assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the fourth enqueue');
    777  });
    778 
    779 }, 'ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately');
    780 
    781 promise_test(t => {
    782 
    783  const randomSource = new RandomPushSource(8);
    784 
    785  const rs = new ReadableStream({
    786    start(c) {
    787      assert_equals(typeof c, 'object', 'c should be an object in start');
    788      assert_equals(typeof c.enqueue, 'function', 'enqueue should be a function in start');
    789      assert_equals(typeof c.close, 'function', 'close should be a function in start');
    790      assert_equals(typeof c.error, 'function', 'error should be a function in start');
    791 
    792      randomSource.ondata = t.step_func(chunk => {
    793        if (!c.enqueue(chunk) <= 0) {
    794          randomSource.readStop();
    795        }
    796      });
    797 
    798      randomSource.onend = c.close.bind(c);
    799      randomSource.onerror = c.error.bind(c);
    800    },
    801 
    802    pull(c) {
    803      assert_equals(typeof c, 'object', 'c should be an object in pull');
    804      assert_equals(typeof c.enqueue, 'function', 'enqueue should be a function in pull');
    805      assert_equals(typeof c.close, 'function', 'close should be a function in pull');
    806 
    807      randomSource.readStart();
    808    }
    809  });
    810 
    811  return readableStreamToArray(rs).then(chunks => {
    812    assert_equals(chunks.length, 8, '8 chunks should be read');
    813    for (const chunk of chunks) {
    814      assert_equals(chunk.length, 128, 'chunk should have 128 bytes');
    815    }
    816  });
    817 
    818 }, 'ReadableStream integration test: adapting a random push source');
    819 
    820 promise_test(() => {
    821 
    822  const rs = sequentialReadableStream(10);
    823 
    824  return readableStreamToArray(rs).then(chunks => {
    825    assert_true(rs.source.closed, 'source should be closed after all chunks are read');
    826    assert_array_equals(chunks, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'the expected 10 chunks should be read');
    827  });
    828 
    829 }, 'ReadableStream integration test: adapting a sync pull source');
    830 
    831 promise_test(() => {
    832 
    833  const rs = sequentialReadableStream(10, { async: true });
    834 
    835  return readableStreamToArray(rs).then(chunks => {
    836    assert_true(rs.source.closed, 'source should be closed after all chunks are read');
    837    assert_array_equals(chunks, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'the expected 10 chunks should be read');
    838  });
    839 
    840 }, 'ReadableStream integration test: adapting an async pull source');