Files
purewhiter--mobilegym/tests/fileSystemSetMetadata.test.ts
wehub-resource-sync 2114b14ee0
Sync main into demo / sync (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:26 +08:00

113 lines
3.6 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
createDirectory,
getNode,
readFile,
setMetadata,
writeFile,
} from '../os/FileSystemService';
// These run against the real FileSystemService. In the vitest `node`
// environment there is no IndexedDB, so the IDB writers (saveFileToDB /
// saveMetadataToDB) gracefully no-op and the module operates purely on its
// in-memory node map — which is exactly the metadata that setMetadata patches.
async function seedFile(path: string): Promise<void> {
await writeFile(path, new Blob(['x'], { type: 'image/jpeg' }), {
mimeType: 'image/jpeg',
createdAt: 1_000,
modifiedAt: 1_000,
});
}
describe('FileSystemService.setMetadata', () => {
it('patches createdAt and modifiedAt in place', async () => {
const path = '/sdcard/DCIM/Camera/setmeta_times.jpg';
await seedFile(path);
const updated = await setMetadata(path, {
createdAt: 1_679_713_540_000,
modifiedAt: 1_679_713_540_000,
});
expect(updated).not.toBeNull();
const node = getNode(path)!;
expect(node.createdAt).toBe(1_679_713_540_000);
expect(node.modifiedAt).toBe(1_679_713_540_000);
});
it('only writes the fields present in the patch', async () => {
const path = '/sdcard/DCIM/Camera/setmeta_partial.jpg';
await seedFile(path);
await setMetadata(path, { modifiedAt: 2_000 });
const node = getNode(path)!;
expect(node.modifiedAt).toBe(2_000);
expect(node.createdAt).toBe(1_000); // untouched
});
it('does not touch the blob or storage backend', async () => {
const path = '/sdcard/DCIM/Camera/setmeta_storage.jpg';
await seedFile(path);
const before = getNode(path)!;
const storageBefore = before.storage;
const sizeBefore = before.size;
await setMetadata(path, { modifiedAt: 3_000 });
const after = getNode(path)!;
expect(after.storage).toBe(storageBefore);
expect(after.size).toBe(sizeBefore);
});
it('ignores structural / internal fields not on the whitelist', async () => {
const path = '/sdcard/DCIM/Camera/setmeta_guard.jpg';
await seedFile(path);
const before = getNode(path)!;
// A caller bypassing the type with `as never` must not be able to corrupt
// identity (id/path) or storage/size invariants.
await setMetadata(path, {
modifiedAt: 4_000,
id: 'evil',
path: '/evil',
storage: 'preset',
size: 999_999,
} as never);
const after = getNode(path)!;
expect(after.modifiedAt).toBe(4_000); // whitelisted field applied
expect(after.id).toBe(before.id);
expect(after.path).toBe(path);
expect(after.storage).toBe(before.storage);
expect(after.size).toBe(before.size);
// The rogue path was not registered as a new node.
expect(getNode('/evil')).toBeNull();
});
it('updates timestamps even when the blob is unavailable', async () => {
const path = '/sdcard/DCIM/Camera/setmeta_noblob.jpg';
await seedFile(path);
// Blob was never persisted (no IndexedDB in this env), so read() yields null
// — the exact scenario the old read-then-write workaround skipped silently.
expect(await readFile(path)).toBeNull();
const updated = await setMetadata(path, { modifiedAt: 5_000 });
expect(updated).not.toBeNull();
expect(getNode(path)!.modifiedAt).toBe(5_000);
});
it('returns null for a missing path', async () => {
expect(await setMetadata('/sdcard/does_not_exist.jpg', { modifiedAt: 1 })).toBeNull();
});
it('returns null for a directory', async () => {
const dir = '/sdcard/setmeta_dir';
await createDirectory(dir);
expect(await setMetadata(dir, { modifiedAt: 1 })).toBeNull();
});
});