Files
core-js/tests/unit-global/esnext.iterator.chunks.js
Yarchik 852f979165 fix: throw TypeError for non-integral Infinity chunk/window size in Iterator.prototype.chunks/windows
The Iterator Chunking proposal requires a TypeError when the size is not
an integral Number before the [1, 2^32-1] RangeError check. ECMA-262
defines an integral Number as finite, so +/-Infinity is not integral and
must throw TypeError. The previous guard used Math.floor(size) !== size,
which is false for Infinity (Math.floor(Infinity) === Infinity), letting
+/-Infinity fall through to the range check and throw RangeError instead.

Use the finite-aware isIntegralNumber helper so +/-Infinity yields
TypeError, while -0/0/-1/2^32/2^53 keep throwing RangeError and valid
sizes in [1, 2^32-1] still pass.
2026-07-01 23:42:39 +01:00

53 lines
2.7 KiB
JavaScript

import { STRICT } from '../helpers/constants.js';
import { createIterator } from '../helpers/helpers.js';
const { from } = Array;
QUnit.test('Iterator#chunks', assert => {
const { chunks } = Iterator.prototype;
assert.isFunction(chunks);
assert.arity(chunks, 1);
assert.name(chunks, 'chunks');
assert.looksNative(chunks);
assert.nonEnumerable(Iterator.prototype, 'chunks');
assert.arrayEqual(from(chunks.call(createIterator([1, 2, 3]), 2)), [[1, 2], [3]], 'basic functionality #1');
assert.arrayEqual(from(chunks.call(createIterator([1, 2, 3, 4]), 2)), [[1, 2], [3, 4]], 'basic functionality #2');
assert.arrayEqual(from(chunks.call(createIterator([]), 2)), [], 'basic functionality on empty iterable');
const it = createIterator([1, 2, 3]);
const result = chunks.call(it, 3);
assert.isIterable(result, 'returns iterable');
assert.isIterator(result, 'returns iterator');
assert.true(result instanceof Iterator, 'returns iterator');
assert.deepEqual(result.next(), { done: false, value: [1, 2, 3] }, '.next with active inner iterator result');
assert.deepEqual(result.return(), { done: true, value: undefined }, '.return with active inner iterator result');
assert.deepEqual(result.next(), { done: true, value: undefined }, '.next on closed iterator');
if (STRICT) {
assert.throws(() => chunks.call('', 1), TypeError, 'iterable non-object this');
assert.throws(() => chunks.call(undefined, 1), TypeError, 'non-iterable-object this #1');
assert.throws(() => chunks.call(null, 1), TypeError, 'non-iterable-object this #2');
assert.throws(() => chunks.call(5, 1), TypeError, 'non-iterable-object this #3');
}
assert.throws(() => chunks.call(it), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, '2'), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, 2.1), TypeError, 'throws on empty argument');
assert.throws(() => chunks.call(it, Infinity), TypeError, 'throws a TypeError on non-integral Infinity argument');
assert.throws(() => chunks.call(it, -Infinity), TypeError, 'throws a TypeError on non-integral -Infinity argument');
assert.throws(() => chunks.call(it, -1), RangeError, 'throws on negative argument');
assert.throws(() => chunks.call(it, 2 ** 32), RangeError, 'throws on negative argument');
const observableReturn = {
return() {
this.called = true;
return { done: true, value: undefined };
},
};
const itObservable = createIterator([1, 2, 3], observableReturn);
assert.throws(() => chunks.call(itObservable, 0x100000000), RangeError, 'throws on argument more then 2^32 - 1');
assert.true(itObservable.called, 'iterator closed on argument validation error');
});