Files
deepseek-harness/examples/desktop/test/plugin-validation.test.js
T

213 lines
7.8 KiB
JavaScript
Raw Normal View History

// Unit tests for src/main/plugin-validation.js — static overlay validation.
// Uses in-memory fixtures so no dev-clone is required.
'use strict'
const test = require('node:test')
const assert = require('node:assert/strict')
const fs = require('node:fs')
const os = require('node:os')
const path = require('node:path')
const V = require('../src/main/plugin-validation.js')
// A small stand-in for `deepseek-harness-dev/packages/`. We create one group
// with two publishable packages so the workspace scanner has real work.
function makeFakePackagesRoot() {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'dsh-validation-'))
const bash = path.join(root, 'bash', 'bash-local')
const fsGroup = path.join(root, 'fs', 'fs-local')
const stray = path.join(root, 'stray')
fs.mkdirSync(bash, { recursive: true })
fs.mkdirSync(fsGroup, { recursive: true })
fs.mkdirSync(stray, { recursive: true })
fs.writeFileSync(path.join(bash, 'package.json'), JSON.stringify({ name: '@deepseek-ai/dsh-bash-local' }))
fs.writeFileSync(path.join(fsGroup, 'package.json'), JSON.stringify({ name: '@deepseek-ai/dsh-fs-local' }))
// stray/ has no package.json — the scanner must silently skip it.
return root
}
test('scanWorkspacePackages picks up @deepseek-ai/dsh-* names, skips dirs without package.json', () => {
const root = makeFakePackagesRoot()
try {
const names = V.scanWorkspacePackages(root)
assert.ok(names.has('@deepseek-ai/dsh-bash-local'))
assert.ok(names.has('@deepseek-ai/dsh-fs-local'))
assert.equal(names.size, 2)
} finally {
fs.rmSync(root, { recursive: true, force: true })
}
})
test('scanWorkspacePackages: missing dir returns empty set (no throw)', () => {
const names = V.scanWorkspacePackages('/definitely/does/not/exist')
assert.equal(names.size, 0)
})
test('classifyName recognises packages, relative paths, and absolute paths', () => {
assert.equal(V.classifyName('@deepseek-ai/dsh-bash-local'), 'package')
assert.equal(V.classifyName('cordis'), 'package')
assert.equal(V.classifyName('../../foo/bar.ts'), 'relative-path')
assert.equal(V.classifyName('./inline.ts'), 'relative-path')
assert.equal(V.classifyName('/etc/passwd'), 'absolute-path')
assert.equal(V.classifyName(''), 'unknown')
})
test('packageResolves: known package passes', () => {
const known = new Set(['@deepseek-ai/dsh-bash-local'])
const reason = V.packageResolves(
{ id: 'bash', name: '@deepseek-ai/dsh-bash-local' },
{ knownPackages: known, leafDir: '/tmp' },
)
assert.equal(reason, null)
})
test('packageResolves: unknown package fails with a helpful message', () => {
const known = new Set(['@deepseek-ai/dsh-fs-local'])
const reason = V.packageResolves(
{ id: 'bash', name: '@deepseek-ai/dsh-bash-local' },
{ knownPackages: known, leafDir: '/tmp' },
)
assert.match(reason, /package not found/)
})
test('packageResolves: relative path resolves against leafDir', () => {
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'dsh-validation-'))
try {
const target = path.join(home, 'nested', 'plugin.ts')
fs.mkdirSync(path.dirname(target), { recursive: true })
fs.writeFileSync(target, '// hi')
const reason = V.packageResolves(
{ id: 'x', name: './nested/plugin.ts' },
{ knownPackages: new Set(), leafDir: home },
)
assert.equal(reason, null)
} finally {
fs.rmSync(home, { recursive: true, force: true })
}
})
test('packageResolves: missing file surfaces the path', () => {
const reason = V.packageResolves(
{ id: 'x', name: './does-not-exist.ts' },
{ knownPackages: new Set(), leafDir: '/tmp' },
)
assert.match(reason, /file does not exist/)
})
test('editDistance handles identical, empty, and typical inputs', () => {
assert.equal(V.editDistance('abc', 'abc'), 0)
assert.equal(V.editDistance('', 'abc'), 3)
assert.equal(V.editDistance('kitten', 'sitting'), 3)
assert.equal(V.editDistance('bash', 'bosh'), 1)
})
test('validate: clean base + no patches → no diagnostics', () => {
const diags = V.validate({
baseEntries: [
{ id: 'bash', name: '@deepseek-ai/dsh-bash-local', line: 1 },
{ id: 'fs', name: '@deepseek-ai/dsh-fs-local', line: 3 },
],
overlay: { base: '', patches: [] },
knownPackages: new Set(['@deepseek-ai/dsh-bash-local', '@deepseek-ai/dsh-fs-local']),
leafDir: '/tmp',
})
assert.equal(diags.length, 0)
})
test('validate: unknown package on a base entry → error diagnostic with line', () => {
const diags = V.validate({
baseEntries: [{ id: 'bash', name: '@deepseek-ai/does-not-exist', line: 7 }],
overlay: { base: '', patches: [] },
knownPackages: new Set(),
leafDir: '/tmp',
})
const err = diags.find((d) => d.severity === 'error' && d.id === 'bash')
assert.ok(err)
assert.equal(err.line, 7)
assert.match(err.message, /package not found/)
})
test('validate: patch targets an id absent from base → error diagnostic', () => {
const diags = V.validate({
baseEntries: [{ id: 'bash', name: '@deepseek-ai/dsh-bash-local' }],
overlay: { base: '', patches: [{ id: 'ghost', disabled: true, line: 12 }] },
knownPackages: new Set(['@deepseek-ai/dsh-bash-local']),
leafDir: '/tmp',
})
const err = diags.find((d) => d.scope === 'patch' && d.id === 'ghost')
assert.ok(err)
assert.equal(err.line, 12)
assert.match(err.message, /not in the base leaf/)
})
test('validate: new-entry patch with an unknown package → error diagnostic', () => {
const diags = V.validate({
baseEntries: [{ id: 'bash', name: '@deepseek-ai/dsh-bash-local' }],
overlay: { base: '', patches: [{ id: 'custom', name: '@nope/plugin', line: 20 }] },
knownPackages: new Set(['@deepseek-ai/dsh-bash-local']),
leafDir: '/tmp',
})
const err = diags.find((d) => d.id === 'custom')
assert.ok(err)
assert.match(err.message, /package not found/)
})
test('validate: near-duplicate active ids trigger a warn (not error)', () => {
const diags = V.validate({
baseEntries: [
{ id: 'bash-local', name: '@deepseek-ai/dsh-bash-local' },
{ id: 'bash-locel', name: '@deepseek-ai/dsh-bash-local' }, // typo
],
overlay: { base: '', patches: [] },
knownPackages: new Set(['@deepseek-ai/dsh-bash-local']),
leafDir: '/tmp',
})
const near = diags.find((d) => d.severity === 'warn' && /near-duplicate/.test(d.message))
assert.ok(near)
})
test('validate: disabled entries are excluded from near-duplicate check', () => {
const diags = V.validate({
baseEntries: [
{ id: 'bash-local', name: '@deepseek-ai/dsh-bash-local' },
{ id: 'bash-locel', name: '@deepseek-ai/dsh-bash-local' },
],
overlay: { base: '', patches: [{ id: 'bash-locel', disabled: true }] },
knownPackages: new Set(['@deepseek-ai/dsh-bash-local']),
leafDir: '/tmp',
})
const near = diags.find((d) => /near-duplicate/.test(d.message))
assert.equal(near, undefined)
})
test('validate: tool-count warning at configurable threshold', () => {
const many = []
for (let i = 0; i < 5; i++) many.push({ id: `p${i}`, name: '@deepseek-ai/dsh-bash-local' })
const diags = V.validate({
baseEntries: many,
overlay: { base: '', patches: [] },
knownPackages: new Set(['@deepseek-ai/dsh-bash-local']),
leafDir: '/tmp',
toolCountWarnAt: 3,
})
const w = diags.find((d) => /enabled entries/.test(d.message))
assert.ok(w)
assert.equal(w.severity, 'warn')
})
test('validate: duplicate id in base → error', () => {
const diags = V.validate({
baseEntries: [
{ id: 'bash', name: '@deepseek-ai/dsh-bash-local', line: 1 },
{ id: 'bash', name: '@deepseek-ai/dsh-bash-local', line: 5 },
],
overlay: { base: '', patches: [] },
knownPackages: new Set(['@deepseek-ai/dsh-bash-local']),
leafDir: '/tmp',
})
const dup = diags.find((d) => /duplicate id/.test(d.message))
assert.ok(dup)
assert.equal(dup.severity, 'error')
})