// modules/test/test-vfs-checkpoint.js — run: node modules/test/test-vfs-checkpoint.js // Proves the name a checkpoint is SAVED under is the name the UI prints and the name // `rollback` resolves. RED on v4.6.101: two independent new Date().toISOString() calls // made the printed name differ from the stored one, so `checkpoint` then // `rollback ` failed with "checkpoint not found or invalid". const fsMod = require('fs'), path = require('path'); const ROOT = path.join(__dirname, '..', 'core'); // ── guarded stubs for the browser globals the VFS touches ────────────────── const ls = {}; global.localStorage = { getItem: k => (k in ls ? ls[k] : null), setItem: (k, v) => { ls[k] = String(v); }, removeItem: k => { delete ls[k]; }, }; global.indexedDB = { open() { throw new Error('indexedDB not available in test'); }, deleteDatabase() { throw new Error('indexedDB not available in test'); }, }; global.window = global; function loadClass(file, clsName) { const src = fsMod.readFileSync(path.join(ROOT, file), 'utf8'); return new Function(src + '\nreturn ' + clsName + ';')(); } const VirtualFileSystem = loadClass('virtual-fs.js', 'VirtualFileSystem'); const SystemModule = loadClass('module-system.js', 'SystemModule'); function mkFs() { const fs = new VirtualFileSystem(); fs.saveToStorage = () => true; // isolate from timers / compression return fs; } let fails = 0, passes = 0; function ok(name, cond, detail) { if (cond) { passes++; return; } fails++; console.log('FAIL ' + name + (detail ? ' — ' + detail : '')); } // A. checkpoint('') must return the resolved name, and two calls must differ { const fs = mkFs(); const a = fs.checkpoint(''); const b = fs.checkpoint(''); ok('A1 checkpoint returns a name string', typeof a === 'string' && a.length > 0, 'got ' + typeof a + ' ' + a); ok('A2 second name also a string', typeof b === 'string' && b.length > 0, 'got ' + typeof b); ok('A3 two unnamed checkpoints get distinct names', a !== b, 'both=' + a); ok('A4 stored under the returned name', !!fs.fsReadJSON('/_snapshots/checkpoint-' + a + '.json')); } // B. rollback with the returned name must succeed { const fs = mkFs(); fs.mkdirRecursive('/marker'); const name = fs.checkpoint(''); ok('B1 checkpoint-list shows the returned name', fs.listCheckpoints().includes(name), 'name=' + name); ok('B2 rollback(returned name) is true', fs.rollback(name) === true, 'name=' + name); } // C. the `checkpoint` command prints exactly the name it created { const fsv = mkFs(); const out = []; const sys = new SystemModule(); sys.terminal = { print: m => out.push(String(m)), fs: fsv }; sys.registerCommands(); out.length = 0; sys.commands['checkpoint']([]); const line = out.join('\n'); const printed = (line.match(/Checkpoint created:\s*(.+)$/m) || [])[1]; ok('C1 command prints a created name', !!printed, 'output=' + JSON.stringify(line)); const listed = fsv.listCheckpoints(); ok('C2 printed name exists on disk', !!printed && listed.includes(printed.trim()), 'printed=' + printed + ' listed=' + JSON.stringify(listed)); ok('C3 rollback of the printed name succeeds', !!printed && fsv.rollback(printed.trim()) === true); // C4: an explicit name is echoed verbatim out.length = 0; sys.commands['checkpoint'](['myname']); ok('C4 explicit name echoed verbatim', /Checkpoint created:\s*myname\s*$/.test(out.join('\n')), 'output=' + JSON.stringify(out.join('\n'))); } if (fails === 0) { console.log('test-vfs-checkpoint: ' + passes + ' passed, 0 failed'); } else { console.log('test-vfs-checkpoint: ' + passes + ' passed, ' + fails + ' FAILED'); process.exit(1); }