summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/streams/transform-streams/strategies.any.js
blob: 57e113e668ce2478a654a4e5ae5c9872e002c7fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// META: global=window,worker,shadowrealm
// META: script=../resources/recording-streams.js
// META: script=../resources/test-utils.js
'use strict';

// Here we just test that the strategies are correctly passed to the readable and writable sides. We assume that
// ReadableStream and WritableStream will correctly apply the strategies when they are being used by a TransformStream
// and so it isn't necessary to repeat their tests here.

test(() => {
  const ts = new TransformStream({}, { highWaterMark: 17 });
  assert_equals(ts.writable.getWriter().desiredSize, 17, 'desiredSize should be 17');
}, 'writableStrategy highWaterMark should work');

promise_test(() => {
  const ts = recordingTransformStream({}, undefined, { highWaterMark: 9 });
  const writer = ts.writable.getWriter();
  for (let i = 0; i < 10; ++i) {
    writer.write(i);
  }
  return delay(0).then(() => {
    assert_array_equals(ts.events, [
      'transform', 0, 'transform', 1, 'transform', 2, 'transform', 3, 'transform', 4,
      'transform', 5, 'transform', 6, 'transform', 7, 'transform', 8],
                        'transform() should have been called 9 times');
  });
}, 'readableStrategy highWaterMark should work');

promise_test(t => {
  let writableSizeCalled = false;
  let readableSizeCalled = false;
  let transformCalled = false;
  const ts = new TransformStream(
    {
      transform(chunk, controller) {
        t.step(() => {
          transformCalled = true;
          assert_true(writableSizeCalled, 'writableStrategy.size() should have been called');
          assert_false(readableSizeCalled, 'readableStrategy.size() should not have been called');
          controller.enqueue(chunk);
          assert_true(readableSizeCalled, 'readableStrategy.size() should have been called');
        });
      }
    },
    {
      size() {
        writableSizeCalled = true;
        return 1;
      }
    },
    {
      size() {
        readableSizeCalled = true;
        return 1;
      },
      highWaterMark: Infinity
    });
  return ts.writable.getWriter().write().then(() => {
    assert_true(transformCalled, 'transform() should be called');
  });
}, 'writable should have the correct size() function');

test(() => {
  const ts = new TransformStream();
  const writer = ts.writable.getWriter();
  assert_equals(writer.desiredSize, 1, 'default writable HWM is 1');
  writer.write(undefined);
  assert_equals(writer.desiredSize, 0, 'default chunk size is 1');
}, 'default writable strategy should be equivalent to { highWaterMark: 1 }');

promise_test(t => {
  const ts = new TransformStream({
    transform(chunk, controller) {
      return t.step(() => {
        assert_equals(controller.desiredSize, 0, 'desiredSize should be 0');
        controller.enqueue(undefined);
        // The first chunk enqueued is consumed by the pending read().
        assert_equals(controller.desiredSize, 0, 'desiredSize should still be 0');
        controller.enqueue(undefined);
        assert_equals(controller.desiredSize, -1, 'desiredSize should be -1');
      });
    }
  });
  const writePromise = ts.writable.getWriter().write();
  return ts.readable.getReader().read().then(() => writePromise);
}, 'default readable strategy should be equivalent to { highWaterMark: 0 }');

test(() => {
  assert_throws_js(RangeError, () => new TransformStream(undefined, { highWaterMark: -1 }),
                   'should throw RangeError for negative writableHighWaterMark');
  assert_throws_js(RangeError, () => new TransformStream(undefined, undefined, { highWaterMark: -1 }),
                   'should throw RangeError for negative readableHighWaterMark');
  assert_throws_js(RangeError, () => new TransformStream(undefined, { highWaterMark: NaN }),
                   'should throw RangeError for NaN writableHighWaterMark');
  assert_throws_js(RangeError, () => new TransformStream(undefined, undefined, { highWaterMark: NaN }),
                   'should throw RangeError for NaN readableHighWaterMark');
}, 'a RangeError should be thrown for an invalid highWaterMark');

const objectThatConvertsTo42 = {
  toString() {
    return '42';
  }
};

test(() => {
  const ts = new TransformStream(undefined, { highWaterMark: objectThatConvertsTo42 });
  const writer = ts.writable.getWriter();
  assert_equals(writer.desiredSize, 42, 'writable HWM is 42');
}, 'writableStrategy highWaterMark should be converted to a number');

test(() => {
  const ts = new TransformStream({
    start(controller) {
      assert_equals(controller.desiredSize, 42, 'desiredSize should be 42');
    }
  }, undefined, { highWaterMark: objectThatConvertsTo42 });
}, 'readableStrategy highWaterMark should be converted to a number');

promise_test(t => {
  const ts = new TransformStream(undefined, undefined, {
    size() { return NaN; },
    highWaterMark: 1
  });
  const writer = ts.writable.getWriter();
  return promise_rejects_js(t, RangeError, writer.write(), 'write should reject');
}, 'a bad readableStrategy size function should cause writer.write() to reject on an identity transform');

promise_test(t => {
  const ts = new TransformStream({
    transform(chunk, controller) {
      // This assert has the important side-effect of catching the error, so transform() does not throw.
      assert_throws_js(RangeError, () => controller.enqueue(chunk), 'enqueue should throw');
    }
  }, undefined, {
    size() {
      return -1;
    },
    highWaterMark: 1
  });

  const writer = ts.writable.getWriter();
  return writer.write().then(() => {
    return Promise.all([
      promise_rejects_js(t, RangeError, writer.ready, 'ready should reject'),
      promise_rejects_js(t, RangeError, writer.closed, 'closed should reject'),
      promise_rejects_js(t, RangeError, ts.readable.getReader().closed, 'readable closed should reject')
    ]);
  });
}, 'a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() ' +
   'catches the exception');