import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { runInNewContext } from 'node:vm'; test('installer accepts the release host and rejects unverified hosts before writing', () => { const source = readFileSync(new URL('./install-preview-download.mjs', import.meta.url), 'utf8') .replace(/^import .*;$/gm, '').replaceAll('import.meta.url', JSON.stringify(import.meta.url)); const release = JSON.parse(readFileSync(new URL('../release.json', import.meta.url))); for (const version of [release.version, '0.2.1-rc.2', '0.2.1-rc.4', 'next']) { const calls = []; const run = () => runInNewContext(source, { URL, readFileSync: () => JSON.stringify({ version }), mkdirSync: (...args) => calls.push(['mkdir', ...args]), cpSync: (...args) => calls.push(['copy', ...args]), execFileSync: (...args) => calls.push(['exec', ...args]), }); if (version === release.version) { run(); assert.deepEqual(calls.map(call => call[0]), ['mkdir', 'copy', 'exec']); assert.equal(calls[2][1], 'tar'); assert.equal(calls[2][2][1], '/usr/local/lib/dsh-mgr/dsh-preview-download-1.0.1.tgz'); } else { assert.throws(run, /Unverified preview download host/); assert.equal(calls.length, 0); } } }); function load() { let plugin; runInNewContext(readFileSync(new URL('./preview-download/client.js', import.meta.url), 'utf8'), { Uint8Array, window: { __ModuleLoader__: { load({ id, factory }) { assert.equal(id, 'dsh-preview-download'); plugin = factory(() => ({})); } } } }); return plugin; } test('download passes exact session/path/signal to authorized complete-file RPC', async () => { const plugin = load(); const data = new Uint8Array([0, 255, 10]); const signal = new AbortController().signal; const remote = { workspaceFiles: { async readBytes(...args) { assert.equal(args[0], 'session-A'); assert.equal(args[1], '/workspace/中文.pptx'); assert.equal(Object.keys(args[2]).length, 0); assert.equal(args[3], signal); return { ok: true, value: { offset: 0, eof: true, bytes: 3, data } }; } } }; assert.equal(await plugin.readOriginal(remote, 'session-A', '/workspace/中文.pptx', signal), data); assert.equal(plugin.filename('/workspace/中文.pptx'), '中文.pptx'); assert.equal(plugin.filename('C:' + String.fromCharCode(92) + 'folder' + String.fromCharCode(92) + 'file.docx'), 'file.docx'); }); test('denied, partial, size mismatch and cancelled reads never produce download data', async () => { const plugin = load(); for (const result of [ { ok: false, error: { code: 'gateway/forbidden' } }, { ok: true, value: { offset: 0, eof: false, data: new Uint8Array() } }, { ok: true, value: { offset: 0, eof: true, bytes: 5, data: new Uint8Array(2) } } ]) { await assert.rejects(plugin.readOriginal({ workspaceFiles: { readBytes: async () => result } }, 's', '/file', new AbortController().signal)); } const controller = new AbortController(); controller.abort(); await assert.rejects(plugin.readOriginal({ workspaceFiles: { readBytes: async () => ({ ok: true, value: {} }) } }, 's', '/file', controller.signal)); }); test('plugin registers only the supported preview action slot', () => { const plugin = load(); let registration; plugin.apply({ effect: fn => fn(), locale: { register: () => () => {} }, remote: {}, slots: { inject(name, fn) { assert.equal(name, 'sidebar.right.tab.document.actions'); return fn(); }, register(options, component) { registration = options; assert.equal(typeof component, 'function'); return () => {}; } } }); assert.equal(registration.id, 'dsh-preview-download'); assert.equal(typeof registration.inject('session-A').download, 'function'); }); test('registered download declares every service used by its callback', async () => { const plugin = load(); assert.ok(plugin.inject.includes('remote')); assert.ok(plugin.inject.includes('remote.workspaceFiles')); let registration; let calls = 0; const data = new Uint8Array([1, 2, 255]); const ctx = { effect: fn => fn(), locale: { register: () => () => {} }, slots: { inject: (_name, fn) => fn(), register(options) { registration = options; return () => {}; } }, get remote() { assert.ok(plugin.inject.includes('remote'), 'Cordis requires explicit remote injection'); return { workspaceFiles: { async readBytes(session, path) { assert.equal(session, 'session-A'); assert.equal(path, '/file.bin'); calls++; return { ok: true, value: { offset: 0, eof: true, bytes: 3, data } }; } } }; } }; plugin.apply(ctx); assert.equal(await registration.inject('session-A').download('/file.bin', new AbortController().signal), data); assert.equal(calls, 1); });