• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// META: global=window,worker
2'use strict';
3
4// Due to the limitations of floating-point precision, the calculation of desiredSize sometimes gives different answers
5// than adding up the items in the queue would. It is important that implementations give the same result in these edge
6// cases so that developers do not come to depend on non-standard behaviour. See
7// https://github.com/whatwg/streams/issues/582 and linked issues for further discussion.
8
9promise_test(() => {
10  const { reader, controller } = setupTestStream();
11
12  controller.enqueue(2);
13  assert_equals(controller.desiredSize, 0 - 2, 'desiredSize must be -2 after enqueueing such a chunk');
14
15  controller.enqueue(Number.MAX_SAFE_INTEGER);
16  assert_equals(controller.desiredSize, 0 - Number.MAX_SAFE_INTEGER - 2,
17    'desiredSize must be calculated using double-precision floating-point arithmetic (adding a second chunk)');
18
19  return reader.read().then(() => {
20    assert_equals(controller.desiredSize, 0 - Number.MAX_SAFE_INTEGER - 2 + 2,
21      'desiredSize must be calculated using double-precision floating-point arithmetic (subtracting a chunk)');
22
23    return reader.read();
24  }).then(() => {
25    assert_equals(controller.desiredSize, 0, '[[queueTotalSize]] must clamp to 0 if it becomes negative');
26  });
27}, 'Floating point arithmetic must manifest near NUMBER.MAX_SAFE_INTEGER (total ends up positive)');
28
29promise_test(() => {
30  const { reader, controller } = setupTestStream();
31
32  controller.enqueue(1e-16);
33  assert_equals(controller.desiredSize, 0 - 1e-16, 'desiredSize must be -1e16 after enqueueing such a chunk');
34
35  controller.enqueue(1);
36  assert_equals(controller.desiredSize, 0 - 1e-16 - 1,
37    'desiredSize must be calculated using double-precision floating-point arithmetic (adding a second chunk)');
38
39  return reader.read().then(() => {
40    assert_equals(controller.desiredSize, 0 - 1e-16 - 1 + 1e-16,
41      'desiredSize must be calculated using double-precision floating-point arithmetic (subtracting a chunk)');
42
43    return reader.read();
44  }).then(() => {
45    assert_equals(controller.desiredSize, 0, '[[queueTotalSize]] must clamp to 0 if it becomes negative');
46  });
47}, 'Floating point arithmetic must manifest near 0 (total ends up positive, but clamped)');
48
49promise_test(() => {
50  const { reader, controller } = setupTestStream();
51
52  controller.enqueue(1e-16);
53  assert_equals(controller.desiredSize, 0 - 1e-16, 'desiredSize must be -2e16 after enqueueing such a chunk');
54
55  controller.enqueue(1);
56  assert_equals(controller.desiredSize, 0 - 1e-16 - 1,
57    'desiredSize must be calculated using double-precision floating-point arithmetic (adding a second chunk)');
58
59  controller.enqueue(2e-16);
60  assert_equals(controller.desiredSize, 0 - 1e-16 - 1 - 2e-16,
61    'desiredSize must be calculated using double-precision floating-point arithmetic (adding a third chunk)');
62
63  return reader.read().then(() => {
64    assert_equals(controller.desiredSize, 0 - 1e-16 - 1 - 2e-16 + 1e-16,
65      'desiredSize must be calculated using double-precision floating-point arithmetic (subtracting a chunk)');
66
67    return reader.read();
68  }).then(() => {
69    assert_equals(controller.desiredSize, 0 - 1e-16 - 1 - 2e-16 + 1e-16 + 1,
70      'desiredSize must be calculated using double-precision floating-point arithmetic (subtracting a second chunk)');
71
72    return reader.read();
73  }).then(() => {
74    assert_equals(controller.desiredSize, 0 - 1e-16 - 1 - 2e-16 + 1e-16 + 1 + 2e-16,
75      'desiredSize must be calculated using double-precision floating-point arithmetic (subtracting a third chunk)');
76  });
77}, 'Floating point arithmetic must manifest near 0 (total ends up positive, and not clamped)');
78
79promise_test(() => {
80  const { reader, controller } = setupTestStream();
81
82  controller.enqueue(2e-16);
83  assert_equals(controller.desiredSize, 0 - 2e-16, 'desiredSize must be -2e16 after enqueueing such a chunk');
84
85  controller.enqueue(1);
86  assert_equals(controller.desiredSize, 0 - 2e-16 - 1,
87    'desiredSize must be calculated using double-precision floating-point arithmetic (adding a second chunk)');
88
89  return reader.read().then(() => {
90    assert_equals(controller.desiredSize, 0 - 2e-16 - 1 + 2e-16,
91      'desiredSize must be calculated using double-precision floating-point arithmetic (subtracting a chunk)');
92
93    return reader.read();
94  }).then(() => {
95    assert_equals(controller.desiredSize, 0,
96      'desiredSize must be calculated using double-precision floating-point arithmetic (subtracting a second chunk)');
97  });
98}, 'Floating point arithmetic must manifest near 0 (total ends up zero)');
99
100function setupTestStream() {
101  const strategy = {
102    size(x) {
103      return x;
104    },
105    highWaterMark: 0
106  };
107
108  let controller;
109  const rs = new ReadableStream({
110    start(c) {
111      controller = c;
112    }
113  }, strategy);
114
115  return { reader: rs.getReader(), controller };
116}
117