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