From 69c0a3825b7701b6564dce23b9f6931c5add5645 Mon Sep 17 00:00:00 2001 From: Jaco-Ren <144145239+Jaco-Ren@users.noreply.github.com> Date: Mon, 29 Jun 2026 17:46:58 +0800 Subject: [PATCH] fix formatBytes edge cases --- frontend/src/lib/utils.test.ts | 22 +++++++++++ frontend/src/lib/utils.ts | 71 +++++++++++++++++----------------- frontend/src/test/setup.ts | 1 + 3 files changed, 59 insertions(+), 35 deletions(-) create mode 100644 frontend/src/lib/utils.test.ts create mode 100644 frontend/src/test/setup.ts diff --git a/frontend/src/lib/utils.test.ts b/frontend/src/lib/utils.test.ts new file mode 100644 index 0000000..701e134 --- /dev/null +++ b/frontend/src/lib/utils.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from 'vitest' + +import { formatBytes } from './utils' + +describe('formatBytes', () => { + it('formats byte values across supported units', () => { + expect(formatBytes(0)).toBe('0 B') + expect(formatBytes(512)).toBe('512.0 B') + expect(formatBytes(1024)).toBe('1.0 KB') + expect(formatBytes(1024 ** 2)).toBe('1.0 MB') + expect(formatBytes(1024 ** 5)).toBe('1.0 PB') + expect(formatBytes(1024 ** 6)).toBe('1.0 EB') + }) + + it('handles invalid or out-of-range values without undefined units', () => { + expect(formatBytes(-1)).toBe('–') + expect(formatBytes(Number.NaN)).toBe('–') + expect(formatBytes(Number.POSITIVE_INFINITY)).toBe('–') + expect(formatBytes(0.5)).toBe('0.5 B') + expect(formatBytes(1024 ** 7)).toBe('1024.0 EB') + }) +}) diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 502c33a..0316300 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1,40 +1,41 @@ -import { type ClassValue, clsx } from 'clsx' -import { twMerge } from 'tailwind-merge' - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} - -export function formatDuration(seconds: number): string { - if (seconds < 60) { - return `${seconds.toFixed(1)}s` - } - const minutes = Math.floor(seconds / 60) - const remainingSeconds = Math.floor(seconds % 60) - if (minutes < 60) { - return `${minutes}m ${remainingSeconds}s` - } - const hours = Math.floor(minutes / 60) - const remainingMinutes = minutes % 60 - return `${hours}h ${remainingMinutes}m` -} - +import { type ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} + +export function formatDuration(seconds: number): string { + if (seconds < 60) { + return `${seconds.toFixed(1)}s` + } + const minutes = Math.floor(seconds / 60) + const remainingSeconds = Math.floor(seconds % 60) + if (minutes < 60) { + return `${minutes}m ${remainingSeconds}s` + } + const hours = Math.floor(minutes / 60) + const remainingMinutes = minutes % 60 + return `${hours}h ${remainingMinutes}m` +} + export function formatBytes(bytes: number): string { + if (!Number.isFinite(bytes) || bytes < 0) return '–' if (bytes === 0) return '0 B' const k = 1024 - const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] - const i = Math.floor(Math.log(bytes) / Math.log(k)) + const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'] + const i = Math.max(0, Math.min(Math.floor(Math.log(bytes) / Math.log(k)), sizes.length - 1)) return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}` } - -export function formatRelativeTime(date: string): string { - const now = new Date() - const then = new Date(date) - const seconds = Math.floor((now.getTime() - then.getTime()) / 1000) - - if (seconds < 60) return 'just now' - if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago` - if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago` - if (seconds < 604800) return `${Math.floor(seconds / 86400)}d ago` - return then.toLocaleDateString() -} + +export function formatRelativeTime(date: string): string { + const now = new Date() + const then = new Date(date) + const seconds = Math.floor((now.getTime() - then.getTime()) / 1000) + + if (seconds < 60) return 'just now' + if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago` + if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago` + if (seconds < 604800) return `${Math.floor(seconds / 86400)}d ago` + return then.toLocaleDateString() +} diff --git a/frontend/src/test/setup.ts b/frontend/src/test/setup.ts new file mode 100644 index 0000000..a9d0dd3 --- /dev/null +++ b/frontend/src/test/setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/vitest'