aboutsummaryrefslogtreecommitdiff
path: root/modules/test/test-fs-mv-cp-guard.js
blob: 369882da5a78643f5645e2028df93980905937f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// modules/test/test-fs-mv-cp-guard.js — run: node
// Proves MAINT-010 (mv/cp must not destroy a directory node) and MAINT-016 (ls -l <path>)
// against the real classes, no browser.
const fsMod = require('fs'), path = require('path');
const ROOT = path.join(__dirname, '..', 'core');
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('no idb'); }, deleteDatabase() { throw new Error('no idb'); } };
global.window = global;

function load(file, cls) {
    return new Function(fsMod.readFileSync(path.join(ROOT, file), 'utf8') + '\nreturn ' + cls + ';')();
}
const VFS = load('virtual-fs.js', 'VirtualFileSystem');
const FSModule = load('module-fs.js', 'FileSystemModule');

function mk() {
    const out = [];
    const vfs = new VFS();
    vfs.saveToStorage = () => true;
    const term = { print: (m, t) => out.push({ text: String(m), type: t || '' }), fs: vfs };
    const mod = new FSModule();
    mod.terminal = term;
    mod.registerCommands();
    return { vfs, mod, out };
}

let fails = 0, passes = 0;
function ok(name, cond, detail) {
    if (cond) { passes++; return; }
    fails++;
    console.log('FAIL ' + name + (detail ? ' — ' + detail : ''));
}

// A. mv a file over a directory must refuse and leave the children alone
{
    const { vfs, mod, out } = mk();
    vfs.mkdirRecursive('/docs');
    vfs.writeFile('/docs/keep.txt', 'precious');
    vfs.writeFile('/report.txt', 'x');
    out.length = 0;
    mod.commands['mv'](['/report.txt', '/docs']);
    const msg = out.map(o => o.text).join(' ');
    ok('A1 mv onto a directory is refused', /is a directory/.test(msg), msg);
    ok('A2 destination children intact', vfs.readFile('/docs/keep.txt') === 'precious');
    ok('A3 source still there', vfs.readFile('/report.txt') === 'x');
}

// B. cp over a directory must refuse too
{
    const { vfs, mod, out } = mk();
    vfs.mkdirRecursive('/docs');
    vfs.writeFile('/docs/keep.txt', 'precious');
    vfs.writeFile('/report.txt', 'x');
    out.length = 0;
    mod.commands['cp'](['/report.txt', '/docs']);
    const msg = out.map(o => o.text).join(' ');
    ok('B1 cp onto a directory is refused', /is a directory/.test(msg), msg);
    ok('B2 destination children intact', vfs.readFile('/docs/keep.txt') === 'precious');
}

// C. mv a a is a no-op, not a delete
{
    const { vfs } = mk();
    vfs.writeFile('/a.txt', 'still here');
    ok('C1 mv onto itself returns true', vfs.rename('/a.txt', '/a.txt') === true);
    ok('C2 file survived', vfs.readFile('/a.txt') === 'still here');
}

// D. overwriting a file with a file still works (documented mv behaviour)
{
    const { vfs } = mk();
    vfs.writeFile('/one.txt', '1');
    vfs.writeFile('/two.txt', '2');
    ok('D1 mv over a file succeeds', vfs.rename('/one.txt', '/two.txt') === true);
    ok('D2 new content in place', vfs.readFile('/two.txt') === '1');
    ok('D3 source gone', vfs.readFile('/one.txt') === null);
}

// E. ls -l <path> lists that path, not the cwd (MAINT-016)
{
    const { vfs, mod, out } = mk();
    vfs.mkdirRecursive('/work');
    vfs.writeFile('/work/inside.txt', 'x');
    vfs.writeFile('/cwd-only.txt', 'y');
    vfs.currentPath = [];
    out.length = 0;
    mod.commands['ls'](['-l', '/work']);
    const text = out.map(o => o.text).join('\n');
    ok('E1 flag-first form lists the given path', /inside\.txt/.test(text) && !/cwd-only\.txt/.test(text), text.replace(/\n/g, ' | '));
}

// F. path-first form keeps working
{
    const { vfs, mod, out } = mk();
    vfs.mkdirRecursive('/work');
    vfs.writeFile('/work/inside.txt', 'x');
    out.length = 0;
    mod.commands['ls'](['/work', '-l']);
    const text = out.map(o => o.text).join('\n');
    ok('F1 path-first form still lists the path', /inside\.txt/.test(text), text.replace(/\n/g, ' | '));
}

if (fails === 0) {
    console.log('test-fs-mv-cp-guard: ' + passes + ' passed, 0 failed');
} else {
    console.log('test-fs-mv-cp-guard: ' + passes + ' passed, ' + fails + ' FAILED');
    process.exit(1);
}