import { assert } from 'chai'; import { trunc, isqrt, isMulOverflow, isAddOverflow, isSubOverflow, isInteger, isSafeInteger, MAX_INT32, MIN_INT32, MAX_UINT32, isInt32, isUint32 } from '../../../lib/math/integer'; describe('math.integer', () => { describe('trunc', () => { test.each([ [5.5, 5], [-5.5, -5], [Number.MAX_SAFE_INTEGER / 10, 900719925474099], [Number.MAX_SAFE_INTEGER / 10 * -1, -900719925474099], ])('trunc#%#', (x: number, result: number) => { assert.strictEqual(trunc(x), result); }); }); describe('isqrt', () => { test.each([ [0, 0], [1.9, 1], [4.5, 2], [255, 15], [256, 16], [1000, 31], [1024, 32], [1025, 32], [65535, 255], [65536, 256], [Number.MAX_SAFE_INTEGER, 94906265], ])('isqrt#%#', (x: number, result: number) => { assert.strictEqual(isqrt(x), result); }); test('isqrt@first128', () => { [ 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11 ].forEach((value, index) => { assert.strictEqual(isqrt(index + 1), value); }); }); test('isqrt@negative', () => { assert.isNaN(isqrt(-1)); assert.isNaN(isqrt(-2.5)); assert.isNaN(isqrt(-100)); }); }); describe('isMulOverflow', () => { function edgeCases(min: number, max: number) { return [ [max, 0, false, min, max], [0, max, false, min, max], [min, 0, false, min, max], [0, min, false, min, max], [max, 1, false, min, max], [1, max, false, min, max], [min, 1, false, min, max], [1, min, false, min, max], [max, -1, false, min, max], [-1, max, false, min, max], [min, -1, true, min, max], [-1, min, true, min, max], [max, max, true, min, max], [max, min, true, min, max], [min, max, true, min, max], [min, min, true, min, max], ]; } test.each([ [100, 100, false, undefined, undefined], [-100, 100, false, undefined, undefined], [100, -100, false, undefined, undefined], [-100, -100, false, undefined, undefined], // ...edgeCases(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER), ...edgeCases(MIN_INT32, MAX_INT32), ])('isMulOverflow#%#', (a: number, b: number, result: boolean, min: number | undefined, max: number | undefined) => { assert.strictEqual(isMulOverflow(a, b, min, max), result); }); }); describe('isAddOverflow', () => { function edgeCases(min: number, max: number) { return [ [max, max, true, min, max], [min, min, true, min, max], [max, min, false, min, max], [min, max, false, min, max], [max, 1, true, min, max], [1, max, true, min, max], [max, -1, false, min, max], [-1, max, false, min, max], [min, -1, true, min, max], [-1, min, true, min, max], [max - 1, 1, false, min, max], [1, max - 1, false, min, max], [max - 1, -1, false, min, max], [-1, max - 1, false, min, max], [min + 1, -1, false, min, max], [-1, min + 1, false, min, max], ]; } test.each([ [100, 100, false, undefined, undefined], [-100, -100, false, undefined, undefined], ...edgeCases(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER), ...edgeCases(MIN_INT32, MAX_INT32), ])('isAddOverflow#%#', (a: number, b: number, result: boolean, min: number | undefined, max: number | undefined) => { assert.strictEqual(isAddOverflow(a, b, min, max), result); }); }); describe('isSubOverflow', () => { function edgeCases(min: number, max: number) { return [ [max, max, false, min, max], [min, min, false, min, max], [max, min, true, min, max], [min, max, true, min, max], [max, 1, false, min, max], [1, max, false, min, max], [max, -1, true, min, max], [-1, max, false, min, max], [min, 1, true, min, max], [1, min, true, min, max], [min, -1, false, min, max], [-1, min, false, min, max], [max - 1, 1, false, min, max], [1, max - 1, false, min, max], ]; } test.each([ [100, 100, false, undefined, undefined], [-100, -100, false, undefined, undefined], // ...edgeCases(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER), //! \todo fixme ...edgeCases(MIN_INT32, MAX_INT32), ])('isSubOverflow#%#', (a: number, b: number, result: boolean, min: number | undefined, max: number | undefined) => { assert.strictEqual(isSubOverflow(a, b, min, max), result); }); }); describe('isInteger', () => { test.each([ [1, true], [-1, true], [0, true], [-0, false], [1.5, false], [-1.5, false], [Number.MAX_SAFE_INTEGER, true], [Number.MIN_SAFE_INTEGER, true], [Number.MAX_SAFE_INTEGER + 1, true], [Number.MIN_SAFE_INTEGER - 1, true], [NaN, false], [Infinity, false], [-Infinity, false] ])('isInteger#%#', (x: number, result: boolean) => { assert.strictEqual(isInteger(x), result); }); }); describe('isSafeInteger', () => { test.each([ [1, true], [-1, true], [0, true], [-0, false], [1.5, false], [-1.5, false], [Number.MAX_SAFE_INTEGER, true], [Number.MIN_SAFE_INTEGER, true], [Number.MAX_SAFE_INTEGER + 1, false], [Number.MIN_SAFE_INTEGER - 1, false], [NaN, false], [Infinity, false], [-Infinity, false] ])('isInteger#%#', (x: number, result: boolean) => { assert.strictEqual(isSafeInteger(x), result); }); }); describe('isInt32', () => { test.each([ [-Infinity, false], [Infinity, false], [NaN, false], [0, true], [-0, false], [Math.PI, false], [1.005, false], [1, true], [-1, true], [MAX_INT32, true], [MIN_INT32, true], [MAX_INT32 + 1, false], [MAX_INT32 + 0.5, false], [MIN_INT32 - 1, false], [MIN_INT32 - 0.5, false], [MAX_UINT32, false] ])('isInt32#%#', (x: number, result: boolean) => { assert.strictEqual(isInt32(x), result); }); }); describe('isUint32', () => { test.each([ [-Infinity, false], [Infinity, false], [NaN, false], [0, true], [-0, false], [Math.PI, false], [1.005, false], [1, true], [-1, false], [MAX_INT32, true], [MIN_INT32, false], [MAX_INT32 + 1, true], [MAX_INT32 + 0.5, false], [MIN_INT32 - 1, false], [MIN_INT32 - 0.5, false], [MAX_UINT32, true], [MAX_UINT32 - 1, true], [MAX_UINT32 + 1, false], ])('isUint32#%#', (x: number, result: boolean) => { assert.strictEqual(isUint32(x), result); }); }); });