test: Add extensive edge case tests and expand number generation

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-03-14 17:31:55 -06:00
committed by Tanner
parent e32b274e5c
commit 0bf1220c62
+136 -8
View File
@@ -161,12 +161,42 @@ function checkDisplay(expected, message) {
// --- Test Cases ---
const testNumbers = [
0, 1, -1, 5, -5, 0.5, -0.5, 123, -123, 1.23, -1.23,
const basicNumbers = [
0, 1, -1, 2, -2, 5, -5, 10, -10, 0.1, -0.1, 0.2, -0.2, 0.5, -0.5,
123, -123, 1.23, -1.23,
1234567, -1234567, 99999999, -99999999,
1e-6, -1e-6, Math.PI, Math.E
];
const edgeCaseNumbers = [
-0,
Number.MAX_SAFE_INTEGER,
Number.MIN_SAFE_INTEGER,
Math.PI, Math.E,
1e-6, -1e-6, 1e-8, -1e-8,
1e6, -1e6, 1e8, -1e8,
0.1+0.2, // floating point fun
1/3, 2/3, 0.9999999, 1.0000001
];
// Generate some more numbers to reach the target count
const generatedNumbers = [];
for (let i = 1; i <= 20; i++) {
// integers
generatedNumbers.push(i * 123);
generatedNumbers.push(i * -123);
// floats
generatedNumbers.push(i / 10);
generatedNumbers.push(i / -10);
// small floats
generatedNumbers.push(i / 1000);
generatedNumbers.push(i / -1000);
}
const testNumbers = [...new Set([...basicNumbers, ...edgeCaseNumbers, ...generatedNumbers])];
// We need to filter out Infinity/-Infinity for pressNumber helper as they can't be typed.
// They can only appear as results, which we test for separately.
const finiteTestNumbers = testNumbers.filter(n => isFinite(n));
// Helper to press a number, handling negatives
function pressNumber(n) {
const s = String(n);
@@ -187,8 +217,8 @@ const binaryOps = {
};
for (const op in binaryOps) {
for (const a of testNumbers) {
for (const b of testNumbers) {
for (const a of finiteTestNumbers) {
for (const b of finiteTestNumbers) {
if (op === '/' && b === 0) {
test(`Binary Edge Case: ${a} / 0`, () => {
pressNumber(a);
@@ -212,6 +242,85 @@ for (const op in binaryOps) {
}
}
// --- Generated Tests: Operations with non-finite results ---
const smallFiniteTestNumbers = [1, -1, 5, -5, 0, 100, -100]; // for speed
// Test operations that result in Infinity, -Infinity, or NaN, and then continue with another operation
for (const a of smallFiniteTestNumbers) {
// a / 0 -> Infinity/-Infinity/NaN
test(`Non-finite chaining: (${a} / 0) + 5`, () => {
pressNumber(a);
press('/0=');
const intermediate = a/0;
checkDisplay(intermediate);
press('+5=');
checkDisplay(intermediate + 5);
});
test(`Non-finite chaining: (${a} / 0) * 5`, () => {
pressNumber(a);
press('/0=');
const intermediate = a/0;
checkDisplay(intermediate);
press('*5=');
checkDisplay(intermediate * 5);
});
test(`Non-finite chaining: (${a} / 0) * 0`, () => {
pressNumber(a);
press('/0=');
const intermediate = a/0;
checkDisplay(intermediate);
press('*0=');
checkDisplay(intermediate * 0); // Should be NaN
});
test(`Non-finite chaining: (${a} / 0) / 5`, () => {
pressNumber(a);
press('/0=');
const intermediate = a/0;
checkDisplay(intermediate);
press('/5=');
checkDisplay(intermediate / 5);
});
test(`Non-finite chaining: (${a} / 0) / 0`, () => {
pressNumber(a);
press('/0=');
const intermediate = a/0;
checkDisplay(intermediate);
press('/0=');
checkDisplay(intermediate / 0);
});
}
// 0/0 = NaN. Test operations on NaN
test(`Non-finite chaining: (0 / 0) + 5`, () => {
press('0/0=');
checkDisplay(NaN);
press('+5=');
checkDisplay(NaN + 5); // anything + NaN is NaN
});
test(`Non-finite chaining: (0 / 0) * 5`, () => {
press('0/0=');
checkDisplay(NaN);
press('*5=');
checkDisplay(NaN * 5);
});
test(`Non-finite chaining: (0 / 0) / 5`, () => {
press('0/0=');
checkDisplay(NaN);
press('/5=');
checkDisplay(NaN / 5);
});
test(`Non-finite chaining: sqrt(negative) then op`, () => {
press('9N'); // -9
press('r'); // sqrt
checkDisplay(NaN);
press('+1=');
checkDisplay(NaN);
});
// --- Generated Tests: Unary Operations ---
const unaryOps = {
'r': { name: 'sqrt', fn: Math.sqrt },
@@ -221,7 +330,7 @@ const unaryOps = {
};
for (const op in unaryOps) {
for (const a of testNumbers) {
for (const a of finiteTestNumbers) {
if (op === 'r' && a < 0) {
test(`Unary Edge Case: sqrt(${a})`, () => {
pressNumber(a);
@@ -242,7 +351,7 @@ for (const op in unaryOps) {
// --- Generated Tests: Chaining Operations ---
// To keep runtime sane, we'll pick a smaller subset for chaining
const chainNumbers = [0, 1, -5, 0.5, 10, 123];
const chainNumbers = [0, 1, -1, 5, -5, 0.5, -0.5, 10, -10, 123, -123, 1.23];
const chainOps = ['+', '-', '*', '/'];
for (const a of chainNumbers) {
@@ -273,7 +382,7 @@ const trigOps = {
'cos': { fn: Math.cos, name: 'cos' },
'tan': { fn: Math.tan, name: 'tan' },
};
const trigAngles = [0, 30, 45, 60, 90, 180, 270, 360, Math.PI/6, Math.PI/4, Math.PI/2, Math.PI, 3*Math.PI/2, 2*Math.PI];
const trigAngles = [0, 15, 30, 45, 60, 75, 90, 180, 270, 360, -30, -45, -90, -180, 450, 720, Math.PI/6, Math.PI/4, Math.PI/3, Math.PI/2, Math.PI, 3*Math.PI/2, 2*Math.PI, -Math.PI/2, -Math.PI];
// Test in DEG mode (default)
for (const op in trigOps) {
@@ -369,5 +478,24 @@ test('Long number input', () => {
checkDisplay('1234567');
});
test('Input starting with decimal point', () => {
press('.5');
checkDisplay('0.5');
press('*2=');
checkDisplay('1');
});
test('Negative zero handling', () => {
press('0N'); // get -0
checkDisplay(-0);
press('*5');
checkDisplay(-0);
press('=');
checkDisplay(-0);
buttonPress('R'); buttonPress('R');
press('5*-0=');
checkDisplay(-0);
});
// Run all the defined tests
runTests();