aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-10-27 08:32:39 +0100
committerAgando <roduccomm@gmail.com>2026-10-27 08:32:39 +0100
commitf1734dfddd88aad22818911e6e5f00bd68675017 (patch)
treeb43d5002a2c1e6f5f646b7a02e0dab85dfad7b33
parent197ab31e1dc915a991b3d88697e0fc4c294563a8 (diff)
fix(newos4): regression test for checkpoint name round-trip (auto)
Task 3 of plan 2026-10-27_061724-newos4-checkpoint-name-mismatch.md. New modules/test/test-vfs-checkpoint.js loads the real VirtualFileSystem and SystemModule with guarded localStorage/indexedDB/window stubs and asserts: A1-A4 checkpoint('') returns the resolved name; two calls differ; the file exists under the returned name B1-B2 checkpoint-list shows the returned name; rollback(<that name>) is true C1-C4 the `checkpoint` command prints exactly the name it created (and an explicit name verbatim) RED before the fix (v4.6.101): FAIL C2 printed name exists on disk — printed=2026-10-27T07:31:21.575Z listed=["2026-10-27T07:31:21.574Z"] test-vfs-checkpoint: 2 passed, 8 FAILED GREEN after: $ node modules/test/test-vfs-checkpoint.js test-vfs-checkpoint: 10 passed, 0 failed
-rw-r--r--modules/test/test-vfs-checkpoint.js92
1 files changed, 92 insertions, 0 deletions
diff --git a/modules/test/test-vfs-checkpoint.js b/modules/test/test-vfs-checkpoint.js
new file mode 100644
index 0000000..03a8c8a
--- /dev/null
+++ b/modules/test/test-vfs-checkpoint.js
@@ -0,0 +1,92 @@
+// 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 <printed name>` 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);
+}