Download app/tests/local-folder.test.mjs from Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP: direct link, hf CLI and curl.
- Browser
- Download file 9.72 kB
-
https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/local-folder.test.mjs
- Command line
-
hf download hf://spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/app/tests/local-folder.test.mjs
-
curl -L -o local-folder.test.mjs https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/local-folder.test.mjs
9.72 kB
| import test from 'node:test'; | |
| import assert from 'node:assert/strict'; | |
| import fs from 'node:fs/promises'; | |
| import os from 'node:os'; | |
| import path from 'node:path'; | |
| import { LocalFolderFs, displayText } from '../src/local-folder.mjs'; | |
| import { createWorkspace } from '../src/workspace.mjs'; | |
| // OS-backed handle fixture for adapter semantics. Actual browser handle cloning, | |
| // permissions, picker UX, and IndexedDB are covered by the browser suite. | |
| async function fixture(t, initial = { 'README.md': '# Local project\n', 'src/app.js': 'export const answer = 1;\n' }) { | |
| const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pi-folder-test-')); | |
| t.after(() => fs.rm(root, { recursive: true, force: true })); | |
| for (const [name, data] of Object.entries(initial)) { await fs.mkdir(path.dirname(path.join(root, name)), { recursive: true }); await fs.writeFile(path.join(root, name), data); } | |
| let reads = 0, failWrite = false; | |
| const handle = (p, kind) => ({ kind, name: path.basename(p), | |
| async *entries() { for (const item of await fs.readdir(p, { withFileTypes: true })) yield [item.name, handle(path.join(p, item.name), item.isDirectory() ? 'directory' : 'file')]; }, | |
| async getFile() { const stat = await fs.stat(p); return { size: stat.size, lastModified: stat.mtimeMs, async arrayBuffer() { reads++; return new Uint8Array(await fs.readFile(p)).buffer; } }; }, | |
| fixturePath: p, | |
| async isSameEntry(other) { return other.fixturePath === p; }, | |
| async createWritable() { | |
| if (failWrite) throw new DOMException('Write denied', 'NotAllowedError'); | |
| let bytes; | |
| return { async write(data) { bytes = data; }, async close() { await fs.writeFile(p, bytes); }, async abort() {} }; | |
| }, | |
| async removeEntry(name) { await fs.rm(path.join(p, name)); }, | |
| }); | |
| // Install traversal separately so each handle closes over its own path. | |
| function make(p, kind) { | |
| const h = handle(p, kind); | |
| const child = async (name, wanted, create) => { | |
| assert(!name.includes('/') && name !== '..'); const target = path.join(p, name); | |
| let stat; | |
| try { stat = await fs.stat(target); } | |
| catch (e) { if (e.code !== 'ENOENT') throw e; if (!create) throw new DOMException('Missing', 'NotFoundError'); if (wanted === 'directory') await fs.mkdir(target); else await fs.writeFile(target, ''); stat = await fs.stat(target); } | |
| if (stat.isDirectory() !== (wanted === 'directory')) throw new DOMException('Wrong kind', 'TypeMismatchError'); | |
| return make(target, wanted); | |
| }; | |
| h.getDirectoryHandle = (name, { create = false } = {}) => child(name, 'directory', create); | |
| h.getFileHandle = (name, { create = false } = {}) => child(name, 'file', create); | |
| h.entries = async function* () { for (const item of await fs.readdir(p, { withFileTypes: true })) yield [item.name, make(path.join(p, item.name), item.isDirectory() ? 'directory' : 'file')]; }; | |
| return h; | |
| } | |
| const directory = make(root, 'directory'); | |
| return { root, directory, get reads() { return reads; }, denyWrites() { failWrite = true; }, read: name => fs.readFile(path.join(root, name), 'utf8'), write: (name, text) => fs.writeFile(path.join(root, name), text) }; | |
| } | |
| test('Local folder: indexing/listing/stat do not read file bytes; workspace snapshots stay metadata-only', async t => { | |
| const disk = await fixture(t, { 'a.txt': 'hello', 'large.bin': Buffer.alloc(2 * 1024 ** 2), 'node_modules/ignore.js': 'ignored' }); | |
| const local = await LocalFolderFs.open(disk.directory), workspace = createWorkspace({}, undefined, local); | |
| await workspace.ready; | |
| assert.equal(disk.reads, 0); | |
| assert.deepEqual(Object.keys(await workspace.snapshot()), ['/workspace/a.txt', '/workspace/large.bin']); | |
| assert.equal(await workspace.serialize(), null); | |
| const listing = await workspace.bash.exec('ls -l /workspace'); assert.equal(listing.exitCode, 0, listing.stderr); | |
| assert.equal(disk.reads, 0); assert.equal(local.skipped, 1); | |
| assert.equal(await workspace.read('a.txt'), 'hello'); assert.equal(disk.reads, 1); | |
| await assert.rejects(workspace.read('large.bin'), { code: 'FILE_TOO_LARGE' }); | |
| }); | |
| test('Local folder: real Bash and agent tools stage edits, mkdir, copy, rename, delete; Apply writes only staged paths', async t => { | |
| const disk = await fixture(t); | |
| const local = await LocalFolderFs.open(disk.directory), workspace = createWorkspace({}, undefined, local); | |
| await workspace.ready; | |
| await workspace.tools.find(t => t.name === 'edit').execute('', { path: 'src/app.js', oldText: '= 1', newText: '= 2' }); | |
| const result = await workspace.bash.exec("mkdir -p reports/nested; printf 'ok\\n' > reports/nested/result.txt; cp README.md copy.md; mv copy.md moved.md; rm README.md"); | |
| assert.equal(result.exitCode, 0, result.stderr); | |
| assert.equal(await disk.read('src/app.js'), 'export const answer = 1;\n'); | |
| assert.equal(await disk.read('README.md'), '# Local project\n'); | |
| const patches = await local.patches(); assert.equal(patches.length, 6); | |
| assert.equal(await local.apply(), 6); | |
| assert.equal(await disk.read('src/app.js'), 'export const answer = 2;\n'); | |
| assert.equal(await disk.read('moved.md'), '# Local project\n'); | |
| assert.equal(await disk.read('reports/nested/result.txt'), 'ok\n'); | |
| await assert.rejects(disk.read('README.md'), { code: 'ENOENT' }); | |
| assert.equal((await local.patches()).length, 0); | |
| }); | |
| test('Local folder: conflicts preflight all writes, including same-size edits, creations and deletions', async t => { | |
| const disk = await fixture(t); | |
| const local = await LocalFolderFs.open(disk.directory); | |
| await local.writeFile('/README.md', 'changed'); await local.writeFile('/src/app.js', 'staged'); | |
| await disk.write('src/app.js', 'export const answer = 9;\n'); | |
| await assert.rejects(local.apply(), /Conflict/); | |
| assert.equal(await disk.read('README.md'), '# Local project\n'); | |
| assert.equal(await disk.read('src/app.js'), 'export const answer = 9;\n'); | |
| const fresh = await LocalFolderFs.open(disk.directory); | |
| await fresh.writeFile('/new.txt', 'staged'); await disk.write('new.txt', 'external'); | |
| await assert.rejects(fresh.apply(), /Conflict/); assert.equal(await disk.read('new.txt'), 'external'); | |
| const deleted = await LocalFolderFs.open(disk.directory); | |
| await deleted.rm('/README.md'); await disk.write('README.md', 'other editor'); | |
| await assert.rejects(deleted.apply(), /Conflict/); assert.equal(await disk.read('README.md'), 'other editor'); | |
| }); | |
| test('Local folder: staged patches restore with the original baseline, not a newly changed disk file', async t => { | |
| const disk = await fixture(t), local = await LocalFolderFs.open(disk.directory); | |
| await local.writeFile('/src/app.js', 'staged'); await local.mkdir('/new'); await local.writeFile('/new/file', 'new'); | |
| const patches = await local.patches(); | |
| await disk.write('src/app.js', 'external'); | |
| const restored = await LocalFolderFs.open(disk.directory, { patches }); | |
| assert.equal(await restored.readFile('/src/app.js'), 'staged'); | |
| assert.equal(await restored.readFile('/new/file'), 'new'); | |
| await assert.rejects(restored.apply(), /Conflict/); | |
| }); | |
| test('Local folder: failed or cancelled application retains pending edits', async t => { | |
| const disk = await fixture(t), local = await LocalFolderFs.open(disk.directory); | |
| await local.writeFile('/README.md', 'staged'); | |
| await assert.rejects(local.apply(AbortSignal.abort()), { name: 'AbortError' }); | |
| disk.denyWrites(); await assert.rejects(local.apply(), /0 of 1 changes applied/); | |
| assert.equal((await local.patches()).length, 1); | |
| assert.equal(await disk.read('README.md'), '# Local project\n'); | |
| const newFile = await LocalFolderFs.open(disk.directory); | |
| await newFile.writeFile('/new.txt', 'staged'); | |
| await assert.rejects(newFile.apply(), /0 of 1/); | |
| await assert.rejects(disk.read('new.txt'), { code: 'ENOENT' }); | |
| assert.equal((await newFile.patches()).length, 1); | |
| }); | |
| test('Local folder: unsupported operations, excludes, binary editor and traversal do not touch disk', async t => { | |
| const disk = await fixture(t), local = await LocalFolderFs.open(disk.directory), workspace = createWorkspace({}, undefined, local); | |
| await workspace.ready; | |
| for (const method of ['chmod', 'symlink', 'link', 'utimes']) assert.throws(() => local[method]('/README.md', 0o777), /ENOTSUP/); | |
| await assert.rejects(local.rm('/src', { recursive: true }), /not supported/); | |
| await assert.rejects(local.writeFile('/.git/config', 'oops'), /excluded/); | |
| assert.throws(() => displayText(new Uint8Array([0, 1])), { code: 'BINARY_FILE' }); | |
| assert.throws(() => displayText(new Uint8Array([0xff, 0xfe])), { code: 'BINARY_FILE' }); | |
| assert.equal(displayText(new TextEncoder().encode('Café 🐾')), 'Café 🐾'); | |
| await workspace.write('../outside.txt', 'virtual only'); | |
| assert.deepEqual(await local.patches(), []); | |
| await assert.rejects(disk.read('outside.txt'), { code: 'ENOENT' }); | |
| }); | |
| test('Local folder: an in-flight editor preview cannot overwrite a staged tool edit', async t => { | |
| const disk = await fixture(t), local = await LocalFolderFs.open(disk.directory); | |
| let unblock, started; | |
| const gate = new Promise(resolve => { unblock = resolve; }); | |
| const loading = new Promise(resolve => { started = resolve; }); | |
| const load = local.loadOriginal.bind(local); | |
| local.loadOriginal = async path => { started(); await gate; return load(path); }; | |
| const preview = local.readFile('/README.md'); await loading; | |
| const edit = local.writeFile('/README.md', 'new staged version'); | |
| unblock(); await Promise.all([preview, edit]); | |
| assert.equal(await local.readFile('/README.md'), 'new staged version'); | |
| assert.equal(await disk.read('README.md'), '# Local project\n'); | |
| assert.equal((await local.patches()).length, 1); | |
| }); | |