Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/lib/helpers/sizeConvertion.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
9 changes: 7 additions & 2 deletions src/lib/helpers/sizeConvertion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
Expand Down