LibJS: Ensure iterator parameter validation closes underlying iterator

This is a normative change in the ECMA-262 spec. See:
9552f29
f2bad00
This commit is contained in:
Timothy Flynn 2025-04-28 19:03:05 -04:00 committed by Tim Flynn
commit 4d70f6ce1c
Notes: github-actions[bot] 2025-04-29 11:34:08 +00:00
11 changed files with 408 additions and 144 deletions

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "Cannot convert symbol to number");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.drop(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "Cannot convert symbol to number");
expect(closed).toBeTrue();
});
test("called with invalid numbers", () => {
expect(() => {
Iterator.prototype.drop(NaN);

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "predicate is not a function");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.every(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "predicate is not a function");
expect(closed).toBeTrue();
});
test("iterator's next method throws", () => {
function TestError() {}

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "predicate is not a function");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.filter(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "predicate is not a function");
expect(closed).toBeTrue();
});
test("iterator's next method throws", () => {
function TestError() {}

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "predicate is not a function");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.find(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "predicate is not a function");
expect(closed).toBeTrue();
});
test("iterator's next method throws", () => {
function TestError() {}

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "mapper is not a function");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.flatMap(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "mapper is not a function");
expect(closed).toBeTrue();
});
test("iterator's next method throws", () => {
function TestError() {}

View file

@ -2,7 +2,25 @@ describe("errors", () => {
test("called with non-callable object", () => {
expect(() => {
Iterator.prototype.forEach(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "fn is not a function");
}).toThrowWithMessage(TypeError, "procedure is not a function");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.forEach(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "procedure is not a function");
expect(closed).toBeTrue();
});
test("iterator's next method throws", () => {

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "mapper is not a function");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.map(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "mapper is not a function");
expect(closed).toBeTrue();
});
test("iterator's next method throws", () => {
function TestError() {}

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "reducer is not a function");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.reduce(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "reducer is not a function");
expect(closed).toBeTrue();
});
test("iterator's next method throws", () => {
function TestError() {}

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "predicate is not a function");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.some(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "predicate is not a function");
expect(closed).toBeTrue();
});
test("iterator's next method throws", () => {
function TestError() {}

View file

@ -5,6 +5,24 @@ describe("errors", () => {
}).toThrowWithMessage(TypeError, "Cannot convert symbol to number");
});
test("argument validation closes underlying iterator", () => {
let closed = false;
let iterator = {
__proto__: Iterator.prototype,
return() {
closed = true;
return {};
},
};
expect(() => {
iterator.take(Symbol.hasInstance);
}).toThrowWithMessage(TypeError, "Cannot convert symbol to number");
expect(closed).toBeTrue();
});
test("called with invalid numbers", () => {
expect(() => {
Iterator.prototype.take(NaN);