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:
+136
-8
@@ -161,12 +161,42 @@ function checkDisplay(expected, message) {
|
|||||||
|
|
||||||
// --- Test Cases ---
|
// --- Test Cases ---
|
||||||
|
|
||||||
const testNumbers = [
|
const basicNumbers = [
|
||||||
0, 1, -1, 5, -5, 0.5, -0.5, 123, -123, 1.23, -1.23,
|
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,
|
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
|
// Helper to press a number, handling negatives
|
||||||
function pressNumber(n) {
|
function pressNumber(n) {
|
||||||
const s = String(n);
|
const s = String(n);
|
||||||
@@ -187,8 +217,8 @@ const binaryOps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const op in binaryOps) {
|
for (const op in binaryOps) {
|
||||||
for (const a of testNumbers) {
|
for (const a of finiteTestNumbers) {
|
||||||
for (const b of testNumbers) {
|
for (const b of finiteTestNumbers) {
|
||||||
if (op === '/' && b === 0) {
|
if (op === '/' && b === 0) {
|
||||||
test(`Binary Edge Case: ${a} / 0`, () => {
|
test(`Binary Edge Case: ${a} / 0`, () => {
|
||||||
pressNumber(a);
|
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 ---
|
// --- Generated Tests: Unary Operations ---
|
||||||
const unaryOps = {
|
const unaryOps = {
|
||||||
'r': { name: 'sqrt', fn: Math.sqrt },
|
'r': { name: 'sqrt', fn: Math.sqrt },
|
||||||
@@ -221,7 +330,7 @@ const unaryOps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const op in unaryOps) {
|
for (const op in unaryOps) {
|
||||||
for (const a of testNumbers) {
|
for (const a of finiteTestNumbers) {
|
||||||
if (op === 'r' && a < 0) {
|
if (op === 'r' && a < 0) {
|
||||||
test(`Unary Edge Case: sqrt(${a})`, () => {
|
test(`Unary Edge Case: sqrt(${a})`, () => {
|
||||||
pressNumber(a);
|
pressNumber(a);
|
||||||
@@ -242,7 +351,7 @@ for (const op in unaryOps) {
|
|||||||
|
|
||||||
// --- Generated Tests: Chaining Operations ---
|
// --- Generated Tests: Chaining Operations ---
|
||||||
// To keep runtime sane, we'll pick a smaller subset for chaining
|
// 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 = ['+', '-', '*', '/'];
|
const chainOps = ['+', '-', '*', '/'];
|
||||||
|
|
||||||
for (const a of chainNumbers) {
|
for (const a of chainNumbers) {
|
||||||
@@ -273,7 +382,7 @@ const trigOps = {
|
|||||||
'cos': { fn: Math.cos, name: 'cos' },
|
'cos': { fn: Math.cos, name: 'cos' },
|
||||||
'tan': { fn: Math.tan, name: 'tan' },
|
'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)
|
// Test in DEG mode (default)
|
||||||
for (const op in trigOps) {
|
for (const op in trigOps) {
|
||||||
@@ -369,5 +478,24 @@ test('Long number input', () => {
|
|||||||
checkDisplay('1234567');
|
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
|
// Run all the defined tests
|
||||||
runTests();
|
runTests();
|
||||||
|
|||||||
Reference in New Issue
Block a user