Files
fidoca/test/file-browser.test.js

147 lines
5.4 KiB
JavaScript

'use strict';
/**
* Tests for the file-browser helpers in src/file-browser.js.
*
* Run with: node --test
* (or) node --test test/file-browser.test.js
*
* Pure unit tests except for `listEntries`/`readLines`, which read the real
* workspace (ROOT_DIR defaults to the process cwd, i.e. the repo root).
*/
import test from 'node:test';
import assert from 'node:assert/strict';
import {
listEntries,
readLines,
formatMention,
normalizeRange,
windowStart,
parentOf,
baseOf,
} from '../src/file-browser.js';
// ─── mention formatting ───────────────────────────────────────────────────────
test('formatMention: whole file', () => {
assert.equal(formatMention('a/b.js'), '@a/b.js');
});
test('formatMention: single line collapses start==end', () => {
assert.equal(formatMention('a/b.js', 10, 10), '@a/b.js:10');
assert.equal(formatMention('a/b.js', 10, null), '@a/b.js:10');
});
test('formatMention: line range', () => {
assert.equal(formatMention('a/b.js', 10, 20), '@a/b.js:10-20');
});
test('formatMention: normalizes backslashes and trailing slashes', () => {
assert.equal(formatMention('a\\b.js', 1, 2), '@a/b.js:1-2');
assert.equal(formatMention('src/', 1, 2), '@src:1-2');
});
// ─── range normalization ──────────────────────────────────────────────────────
test('normalizeRange: anchor above cursor', () => {
assert.deepEqual(normalizeRange(2, 5), { start: 3, end: 6 });
});
test('normalizeRange: anchor below cursor', () => {
assert.deepEqual(normalizeRange(5, 2), { start: 3, end: 6 });
});
test('normalizeRange: single line', () => {
assert.deepEqual(normalizeRange(4, 4), { start: 5, end: 5 });
});
// ─── windowing ────────────────────────────────────────────────────────────────
test('windowStart: everything fits', () => {
assert.equal(windowStart(0, 5, 200), 0);
assert.equal(windowStart(4, 5, 200), 0);
});
test('windowStart: centers around the cursor', () => {
assert.equal(windowStart(100, 1000, 20), 90);
});
test('windowStart: clamps at the top', () => {
assert.equal(windowStart(0, 1000, 20), 0);
assert.equal(windowStart(3, 1000, 20), 0);
});
test('windowStart: clamps at the bottom', () => {
assert.equal(windowStart(999, 1000, 20), 980);
});
// ─── path helpers ─────────────────────────────────────────────────────────────
test('parentOf / baseOf', () => {
assert.equal(parentOf(''), '');
assert.equal(parentOf('src'), '');
assert.equal(parentOf('src/tools'), 'src');
assert.equal(baseOf('src/tools'), 'tools');
assert.equal(baseOf('README.md'), 'README.md');
});
// ─── listing (real workspace) ─────────────────────────────────────────────────
test('listEntries: dirs before files, dot-dirs and gitignored hidden', () => {
const entries = listEntries('');
const names = entries.map((e) => e.name);
// node_modules is hardcoded-ignored, .git is a dot-dir: both must be absent.
assert.ok(!names.includes('node_modules'), 'node_modules hidden');
assert.ok(!names.includes('.git'), '.git hidden');
// A root listing has no synthetic parent entry.
assert.ok(!names.includes('..'), 'no parent entry at root');
// src/ is a directory and README.md a file: directory must come first.
const srcIdx = names.indexOf('src');
const readmeIdx = names.indexOf('README.md');
assert.ok(srcIdx !== -1, 'src listed');
assert.ok(readmeIdx !== -1, 'README.md listed');
assert.ok(srcIdx < readmeIdx, 'directories sort before files');
const src = entries.find((e) => e.name === 'src');
assert.equal(src.type, 'd');
assert.equal(src.rel, 'src');
const readme = entries.find((e) => e.name === 'README.md');
assert.equal(readme.type, 'f');
assert.equal(readme.rel, 'README.md');
});
test('listEntries: nested listing prepends a parent entry', () => {
const entries = listEntries('src');
assert.equal(entries[0].name, '..');
assert.equal(entries[0].type, 'parent');
assert.equal(entries[0].rel, '');
assert.ok(entries.some((e) => e.name === 'fido.js' && e.type === 'f'));
});
// ─── reading (real workspace) ─────────────────────────────────────────────────
test('readLines: reads a real file into lines', () => {
const { lines, binary } = readLines('README.md');
assert.equal(binary, false);
assert.ok(Array.isArray(lines));
assert.ok(lines.length > 0);
assert.ok(lines[0].includes('FIDO'));
});
test('readLines: rejects paths that escape the workspace', () => {
const res = readLines('../secrets.txt');
assert.equal(res.error, true);
assert.deepEqual(res.lines, []);
});
test('readLines: missing file reports error, not a throw', () => {
const res = readLines('does/not/exist.js');
assert.equal(res.error, true);
assert.deepEqual(res.lines, []);
});