diff --git a/src/lib/helpers/sizeConvertion.test.ts b/src/lib/helpers/sizeConvertion.test.ts new file mode 100644 index 0000000000..2f6e1afc35 --- /dev/null +++ b/src/lib/helpers/sizeConvertion.test.ts @@ -0,0 +1,56 @@ +import { expect, test } from 'vitest'; +import { calculateSize } from '$lib/helpers/sizeConvertion'; + +/* +calculateSize - normal values +*/ +test('formats zero as Bytes', () => { + expect(calculateSize(0)).toEqual('0 Bytes'); +}); + +test('formats byte values under the base', () => { + expect(calculateSize(1)).toEqual('1 Bytes'); + expect(calculateSize(999)).toEqual('999 Bytes'); +}); + +test('scales to the correct unit (base 1000)', () => { + expect(calculateSize(1000)).toEqual('1 KB'); + expect(calculateSize(1500)).toEqual('1.5 KB'); + expect(calculateSize(1_000_000)).toEqual('1 MB'); + expect(calculateSize(123_456_789)).toEqual('123.5 MB'); +}); + +test('scales to the correct unit (base 1024)', () => { + expect(calculateSize(1024, 1, 1024)).toEqual('1 KB'); + expect(calculateSize(1_073_741_824, 1, 1024)).toEqual('1 GB'); +}); + +test('respects the decimals argument', () => { + expect(calculateSize(1500, 0)).toEqual('2 KB'); + expect(calculateSize(1536, 2, 1024)).toEqual('1.5 KB'); +}); + +/* +calculateSize - invalid / edge input +Regression: previously these produced strings like "NaN undefined" / "500 undefined" +because Math.log of a non-finite/negative value yields an out-of-range unit index. +*/ +test('handles non-finite input without emitting "undefined"', () => { + expect(calculateSize(NaN)).toEqual('0 Bytes'); + expect(calculateSize(Infinity)).toEqual('0 Bytes'); + expect(calculateSize(-Infinity)).toEqual('0 Bytes'); +}); + +test('handles nullish input coerced to a number', () => { + // API sizes (e.g. a deployment still building) can be undefined/null at the call site. + expect(calculateSize(undefined as unknown as number)).toEqual('0 Bytes'); + expect(calculateSize(null as unknown as number)).toEqual('0 Bytes'); +}); + +test('handles negative input', () => { + expect(calculateSize(-5)).toEqual('0 Bytes'); +}); + +test('handles sub-1-byte input without an undefined unit', () => { + expect(calculateSize(0.5)).toEqual('0.5 Bytes'); +}); diff --git a/src/lib/helpers/sizeConvertion.ts b/src/lib/helpers/sizeConvertion.ts index 5d1f7c73bc..f3d8845bce 100644 --- a/src/lib/helpers/sizeConvertion.ts +++ b/src/lib/helpers/sizeConvertion.ts @@ -4,11 +4,16 @@ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] as const export type Size = (typeof sizes)[number]; export function calculateSize(bytes: number, decimals = 1, base: 1000 | 1024 = 1000) { - if (bytes === 0) return '0 Bytes'; + // Guard non-finite/negative input (e.g. an undefined API size coerced to NaN): + // without this the log math yields `NaN`/out-of-range indexes and the UI renders + // strings like "NaN undefined" or "500 undefined". + if (!Number.isFinite(bytes) || bytes <= 0) return '0 Bytes'; const dm = decimals < 0 ? 0 : decimals; - const i = Math.floor(Math.log(bytes) / Math.log(base)); + // Clamp the unit index so sub-1-byte and astronomically large values still map to a + // real unit rather than reading `sizes[-1]`/`sizes[9]` as `undefined`. + const i = Math.min(Math.max(Math.floor(Math.log(bytes) / Math.log(base)), 0), sizes.length - 1); return parseFloat((bytes / Math.pow(base, i)).toFixed(dm)) + ' ' + sizes[i]; }