mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
105 lines
3.9 KiB
TypeScript
105 lines
3.9 KiB
TypeScript
import { describe, expect, test } from 'vitest';
|
||
import { humanizeBytes, jsonByteSize, summarizeStorage } from './storage-estimate';
|
||
|
||
describe('summarizeStorage (composition)', () => {
|
||
test('with origin usage: app = usage − snippets − datasets, total = usage', () => {
|
||
const c = summarizeStorage({ usageBytes: 1000, snippetBytes: 100, datasetBytes: 300 });
|
||
expect(c.originMeasured).toBe(true);
|
||
expect(c.totalBytes).toBe(1000);
|
||
expect(c.segments).toEqual([
|
||
{ key: 'snippets', label: 'Snippets', bytes: 100 },
|
||
{ key: 'datasets', label: 'Datasets', bytes: 300 },
|
||
{ key: 'app', label: 'App', bytes: 600 },
|
||
]);
|
||
});
|
||
|
||
test('without origin usage: snippets + datasets only, total is their sum', () => {
|
||
const c = summarizeStorage({ snippetBytes: 100, datasetBytes: 300 });
|
||
expect(c.originMeasured).toBe(false);
|
||
expect(c.totalBytes).toBe(400);
|
||
expect(c.segments.map((s) => s.key)).toEqual(['snippets', 'datasets']);
|
||
});
|
||
|
||
test('usage smaller than measured data falls back to snippets+datasets (estimate lag)', () => {
|
||
const c = summarizeStorage({ usageBytes: 50, snippetBytes: 100, datasetBytes: 300 });
|
||
expect(c.originMeasured).toBe(false);
|
||
expect(c.totalBytes).toBe(400);
|
||
expect(c.segments).toHaveLength(2);
|
||
});
|
||
|
||
test('usage exactly equal to measured data yields a zero-byte app segment', () => {
|
||
const c = summarizeStorage({ usageBytes: 400, snippetBytes: 100, datasetBytes: 300 });
|
||
expect(c.originMeasured).toBe(true);
|
||
expect(c.segments.find((s) => s.key === 'app')?.bytes).toBe(0);
|
||
});
|
||
|
||
test('invalid / negative / non-finite inputs degrade to 0 bytes', () => {
|
||
const c = summarizeStorage({ usageBytes: NaN, snippetBytes: -5, datasetBytes: Infinity });
|
||
expect(c.segments[0].bytes).toBe(0); // snippets
|
||
expect(c.segments[1].bytes).toBe(0); // datasets
|
||
expect(c.originMeasured).toBe(false); // usage NaN → unusable
|
||
expect(c.totalBytes).toBe(0);
|
||
});
|
||
|
||
test('empty workspace: every segment is zero, total zero', () => {
|
||
const c = summarizeStorage({ snippetBytes: 0, datasetBytes: 0 });
|
||
expect(c.totalBytes).toBe(0);
|
||
expect(c.segments.every((s) => s.bytes === 0)).toBe(true);
|
||
});
|
||
});
|
||
|
||
describe('jsonByteSize', () => {
|
||
test('measures the UTF-8 byte length of the JSON serialization', () => {
|
||
expect(jsonByteSize({ a: 1 })).toBe(new TextEncoder().encode('{"a":1}').length);
|
||
});
|
||
|
||
test('counts multi-byte characters by their UTF-8 size', () => {
|
||
// "é" is 2 UTF-8 bytes; JSON.stringify("é") => the 4-byte string «"é"».
|
||
expect(jsonByteSize('é')).toBe(4);
|
||
});
|
||
|
||
test('an unserializable (circular) value degrades to 0', () => {
|
||
const a: Record<string, unknown> = {};
|
||
a.self = a;
|
||
expect(jsonByteSize(a)).toBe(0);
|
||
});
|
||
});
|
||
|
||
describe('humanizeBytes', () => {
|
||
test('zero renders as whole bytes', () => {
|
||
expect(humanizeBytes(0)).toBe('0 B');
|
||
});
|
||
|
||
test('small values stay in whole bytes', () => {
|
||
expect(humanizeBytes(1)).toBe('1 B');
|
||
expect(humanizeBytes(512)).toBe('512 B');
|
||
expect(humanizeBytes(1023)).toBe('1023 B');
|
||
});
|
||
|
||
test('KB boundary (1024) and within KB', () => {
|
||
expect(humanizeBytes(1024)).toBe('1.0 KB');
|
||
expect(humanizeBytes(1536)).toBe('1.5 KB');
|
||
});
|
||
|
||
test('MB boundary and within MB', () => {
|
||
expect(humanizeBytes(1024 * 1024)).toBe('1.0 MB');
|
||
expect(humanizeBytes(5 * 1024 * 1024)).toBe('5.0 MB');
|
||
expect(humanizeBytes(2.5 * 1024 * 1024)).toBe('2.5 MB');
|
||
});
|
||
|
||
test('GB boundary', () => {
|
||
expect(humanizeBytes(1024 * 1024 * 1024)).toBe('1.0 GB');
|
||
});
|
||
|
||
test('caps at the largest unit (TB)', () => {
|
||
expect(humanizeBytes(1024 ** 4)).toBe('1.0 TB');
|
||
expect(humanizeBytes(1024 ** 5)).toBe('1024.0 TB');
|
||
});
|
||
|
||
test('negative and non-finite inputs degrade to 0 B', () => {
|
||
expect(humanizeBytes(-1)).toBe('0 B');
|
||
expect(humanizeBytes(NaN)).toBe('0 B');
|
||
expect(humanizeBytes(Infinity)).toBe('0 B');
|
||
});
|
||
});
|