Files
mdg-filius/packages/core/test/virtualFileSystem.test.ts
T
julian.kiedaischandClaude Opus 5.5 a198d10b4a feat(core): virtual file system and Swift string semantics
The core gains Swift's virtual file system (paths, case-insensitive
lookup that keeps the spelling, quotas, atomic changes, the defaults of
a new device) and the string behaviour the ported code relies on without
saying so. Both are measured in the Swift oracle: 11 file system cases
(the three Swift tests among them) step by step, and trimming, lower
case, equality, ordering and Base64 case by case — whitespace and control
characters over all of Unicode.

Found by measuring:
- Swift trims NEL and ZERO WIDTH SPACE, not the BOM; JS trim() does the
  opposite. The .fls import now trims with swiftTrim.
- lowercased() maps scalar by scalar: a word-final sigma stays σ.
- Foundation decodes "====" and "Y===" as empty data.
- Foundation on Linux counts 24,735 plane-14 scalars as control
  characters, a table artefact; the port keeps Unicode Cc+Cf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:23:45 +00:00

167 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// The virtual file system against the Swift core: every case in
// vfs.cases.json runs in Swift (vfs.swift.json, tools/swift-oracle --vfs);
// each step's result or error and the final entries must match. The cases
// include the three Swift tests on the file system, ported as cases.
import { createHash } from 'node:crypto';
import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import {
VirtualFileSystem,
VirtualFileSystemError,
normalizedAbsolutePath,
type VirtualFileContent,
type VirtualFileEntry,
} from '../src/index.js';
interface Step {
op: string;
path?: string;
to?: string;
name?: string;
text?: string;
size?: number;
byte?: number;
mediaType?: string;
recursive?: boolean;
overwrite?: boolean;
entries?: { path: string; kind: string; text?: string }[];
}
const here = dirname(fileURLToPath(import.meta.url));
const cases = JSON.parse(readFileSync(join(here, 'vfs.cases.json'), 'utf8')) as { name: string; steps: Step[] }[];
const swift = JSON.parse(readFileSync(join(here, 'vfs.swift.json'), 'utf8')) as {
name: string;
results: unknown[];
entries: unknown[];
}[];
function describeEntries(entries: VirtualFileEntry[]): unknown[] {
return entries.map(({ path, content }) => ({ path, ...describeContent(content) }));
}
function describeContent(content: VirtualFileContent): Record<string, unknown> {
switch (content.kind) {
case 'directory':
return { kind: 'directory' };
case 'text':
return { kind: 'text', text: content.text };
case 'binary':
case 'image':
return {
kind: content.kind,
bytes: content.data.length,
mediaType: content.mediaType ?? null,
sha256: createHash('sha256').update(content.data).digest('hex'),
};
}
}
function run(steps: Step[]) {
let fileSystem = new VirtualFileSystem();
const results: unknown[] = [];
for (const step of steps) {
const path = step.path ?? '/';
const bytes = () => new Uint8Array(step.size ?? 0).fill(step.byte ?? 0);
try {
switch (step.op) {
case 'createDirectory':
fileSystem.createDirectory(path, step.recursive ?? false);
break;
case 'writeText':
fileSystem.writeTextFile(path, step.text ?? '', step.overwrite ?? true);
break;
case 'writeBinary':
fileSystem.writeBinaryFile(path, bytes(), step.mediaType, step.overwrite ?? true);
break;
case 'writeImage':
fileSystem.writeImageFile(path, bytes(), step.mediaType ?? 'image/png', step.overwrite ?? true);
break;
case 'copy':
fileSystem.copyItem(path, step.to ?? '/', step.overwrite ?? false);
break;
case 'move':
fileSystem.moveItem(path, step.to ?? '/', step.overwrite ?? false);
break;
case 'rename':
results.push({ ok: fileSystem.renameItem(path, step.name ?? '') });
continue;
case 'delete':
fileSystem.deleteItem(path, step.recursive ?? false);
break;
case 'entry':
results.push({ ok: describeEntries([fileSystem.entry(path)])[0] });
continue;
case 'entries':
results.push({ ok: describeEntries(fileSystem.entries(path)) });
continue;
case 'text':
results.push({ ok: fileSystem.textFile(path) });
continue;
case 'contains':
results.push({ ok: fileSystem.contains(path) });
continue;
case 'normalize':
results.push({ ok: normalizedAbsolutePath(path) });
continue;
case 'default':
fileSystem = VirtualFileSystem.defaultForDevice();
break;
case 'fromEntries':
fileSystem = VirtualFileSystem.fromEntries(
(step.entries ?? []).map((entry) => ({
path: entry.path,
content: entry.kind === 'directory' ? { kind: 'directory' } : { kind: 'text', text: entry.text ?? '' },
})),
);
break;
default:
throw new Error(`unknown step ${step.op}`);
}
results.push({ ok: true });
} catch (error) {
if (!(error instanceof VirtualFileSystemError)) throw error;
results.push({ error: error.code, values: error.values });
}
}
return { results, entries: describeEntries(fileSystem.allEntries()) };
}
describe('virtual file system against Swift', () => {
it('covers every case', () => {
expect(swift.map((result) => result.name)).toEqual(cases.map((item) => item.name));
});
cases.forEach((item, index) => {
it(item.name, () => {
const { results, entries } = run(item.steps);
const expected = swift[index]!;
results.forEach((result, step) => {
expect(result, `step ${step + 1}: ${JSON.stringify(item.steps[step])}`).toEqual(expected.results[step]);
});
expect(entries).toEqual(expected.entries);
});
});
});
describe('virtual file system', () => {
it('leaves itself unchanged when a copy breaks a quota (Swift test)', () => {
const fileSystem = new VirtualFileSystem();
const maximum = new Uint8Array(8 * 1024 * 1024).fill(0x41);
for (const name of ['source', 'destination', 'third', 'fourth']) {
fileSystem.writeBinaryFile(`/${name}.bin`, maximum, 'application/octet-stream');
}
const before = fileSystem.clone();
expect(() => fileSystem.copyItem('/source.bin', '/new.bin', true)).toThrow(VirtualFileSystemError);
expect(fileSystem.equals(before)).toBe(true);
});
it('upgrades the 1×1 black images of older versions, and only those', () => {
const fileSystem = VirtualFileSystem.defaultForDevice();
expect(fileSystem.upgradeLegacyDefaultImages()).toBe(0);
});
});