import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import {
collectPublicHtmlReferences,
findMissingPublicHtmlReferences,
isDownloadLikeReference,
isFilesystemPublicReference,
scanPublicHtmlLinks,
} from './mindspace-public-links.mjs';
test('isFilesystemPublicReference skips external and absolute server paths', () => {
assert.equal(isFilesystemPublicReference('duck.docx'), true);
assert.equal(isFilesystemPublicReference('assets/hero.jpg'), true);
assert.equal(isFilesystemPublicReference('https://example.com/a.docx'), false);
assert.equal(isFilesystemPublicReference('/api/mindspace/v1/assets/a/download'), false);
assert.equal(isFilesystemPublicReference('/MindSpace/u/public/page.html'), false);
});
test('isDownloadLikeReference matches download attr and attachment extensions', () => {
assert.equal(isDownloadLikeReference('report.docx', 'href="report.docx" download'), true);
assert.equal(isDownloadLikeReference('assets/chart.png', 'src="assets/chart.png"'), false);
assert.equal(isDownloadLikeReference('data/report.pdf', 'href="data/report.pdf"'), true);
});
test('collectPublicHtmlReferences downloads-only ignores api src and cover', () => {
const html = `
下载
chart
`;
const all = collectPublicHtmlReferences(html, '/tmp/public');
const downloads = collectPublicHtmlReferences(html, '/tmp/public', { downloadsOnly: true });
assert.deepEqual(
all.map((item) => item.ref).sort(),
['assets/chart.png', 'assets/hero.jpg', 'report.docx'],
);
assert.deepEqual(downloads.map((item) => item.ref), ['report.docx']);
});
test('findMissingPublicHtmlReferences reports missing sibling files', () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ms-links-'));
const htmlPath = path.join(dir, 'report.html');
fs.writeFileSync(htmlPath, '下载');
const missing = findMissingPublicHtmlReferences(htmlPath, null, { downloadsOnly: true });
assert.equal(missing.length, 1);
assert.equal(missing[0].ref, 'report.docx');
fs.writeFileSync(path.join(dir, 'report.docx'), 'doc');
assert.deepEqual(findMissingPublicHtmlReferences(htmlPath, null, { downloadsOnly: true }), []);
});
test('normalizeReferencePath decodes percent-encoded filenames', () => {
const html = 'x';
const refs = collectPublicHtmlReferences(html, '/tmp/public', { downloadsOnly: true });
assert.equal(refs[0]?.ref, '养猪.docx');
});
test('scanPublicHtmlLinks walks MindSpace user public html files', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ms-root-'));
const publicDir = path.join(root, 'user-a', 'public');
fs.mkdirSync(publicDir, { recursive: true });
fs.writeFileSync(path.join(publicDir, 'page.html'), 'pdf');
const issues = scanPublicHtmlLinks(root, { downloadsOnly: true });
assert.equal(issues.length, 1);
assert.match(issues[0].htmlPath, /page\.html$/);
assert.equal(issues[0].ref, 'missing.pdf');
});