mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-20 23:11:46 +02:00
* test(lib): cover feedback-links routes and payload Pins the three public issue routes to the ECC repository and checks each template name actually exists under .github/ISSUE_TEMPLATE. Also locks the ecc.feedback.v1 payload shape, the no-diagnostics-upload promise, and that every call returns fresh copies so a caller cannot alter the frozen route table. * test(lib): cover cursor-agent-names prefixing and path handling Pins the ecc- prefix rule the Cursor install applies to agent files: idempotent, lowercase-prefix only, empty names pass through. Covers the relative path variant across backslash, repeated, and trailing separators, and that a leading separator cannot re-root the destination under the target agents directory. * test(lib): cover agent-tool-map Pi mapping and authority invariant Pins the Claude to Pi tool table: six core tools, every target a real Pi built-in, and read-only tools never escalating to bash, edit, or write. Covers the unsupported path for MCP, web, unknown, empty, and non-string names, and that prototype member names like constructor are not treated as table hits. * test(lib): cover compute-sponsor URL and passive copy Pins the compute URL to the bare https route with no path, query, or credentials, and that the sponsor copy links it exactly once and nowhere else. Locks the wording that keeps the link passive, keeps the ecc ito find bridge opt-in and non-reserving, and does not claim managed inference is live. The existing surface test only reads docs and CLI output, so the module itself had no direct test. * test(lib): cover invocation-environment precedence and isolation Pins the three branches every install path relies on: an explicit env is copied and wins, a scoped homeDir yields an empty environment so ambient variables cannot leak into a contained install, and anything else snapshots process.env. Also checks the copy is shallow, own-keys only, and never writes back.
113 lines
4.6 KiB
JavaScript
113 lines
4.6 KiB
JavaScript
'use strict';
|
|
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const { FEEDBACK_ROUTES, exitFeedbackLines, getFeedbackPayload, problemReportLines } = require('../../scripts/lib/feedback-links');
|
|
|
|
const ISSUE_TEMPLATE_DIR = path.join(__dirname, '..', '..', '.github', 'ISSUE_TEMPLATE');
|
|
const ISSUES_NEW_URL = 'https://github.com/affaan-m/ECC/issues/new';
|
|
|
|
test('every route is a new-issue URL on the ECC repository with only a template query', () => {
|
|
assert.deepEqual(Object.keys(FEEDBACK_ROUTES).sort(), ['feature', 'feedback', 'problem']);
|
|
for (const [name, route] of Object.entries(FEEDBACK_ROUTES)) {
|
|
const parsed = new URL(route);
|
|
assert.equal(parsed.protocol, 'https:', `${name} protocol`);
|
|
assert.equal(parsed.hostname, 'github.com', `${name} host`);
|
|
assert.equal(parsed.pathname, '/affaan-m/ECC/issues/new', `${name} path`);
|
|
assert.equal(parsed.username, '', `${name} username`);
|
|
assert.equal(parsed.password, '', `${name} password`);
|
|
assert.equal(parsed.hash, '', `${name} hash`);
|
|
assert.deepEqual([...parsed.searchParams.keys()], ['template'], `${name} query keys`);
|
|
}
|
|
});
|
|
|
|
test('every route points at an issue template that exists in the repository', () => {
|
|
for (const [name, route] of Object.entries(FEEDBACK_ROUTES)) {
|
|
const template = new URL(route).searchParams.get('template');
|
|
assert.match(template, /^[a-z-]+\.yml$/, `${name} template name`);
|
|
assert.ok(fs.existsSync(path.join(ISSUE_TEMPLATE_DIR, template)), `${name} route names ${template}, which is not in .github/ISSUE_TEMPLATE`);
|
|
}
|
|
});
|
|
|
|
test('each route maps to the intended template', () => {
|
|
assert.equal(FEEDBACK_ROUTES.problem, `${ISSUES_NEW_URL}?template=install-problem.yml`);
|
|
assert.equal(FEEDBACK_ROUTES.feedback, `${ISSUES_NEW_URL}?template=quick-feedback.yml`);
|
|
assert.equal(FEEDBACK_ROUTES.feature, `${ISSUES_NEW_URL}?template=feature-request.yml`);
|
|
});
|
|
|
|
test('the route table is frozen', () => {
|
|
assert.ok(Object.isFrozen(FEEDBACK_ROUTES));
|
|
assert.throws(() => {
|
|
FEEDBACK_ROUTES.problem = 'https://example.invalid/';
|
|
}, TypeError);
|
|
assert.throws(() => {
|
|
FEEDBACK_ROUTES.extra = 'https://example.invalid/';
|
|
}, TypeError);
|
|
assert.equal(FEEDBACK_ROUTES.problem, `${ISSUES_NEW_URL}?template=install-problem.yml`);
|
|
});
|
|
|
|
test('the payload declares the public schema and no diagnostics upload', () => {
|
|
assert.deepEqual(getFeedbackPayload(), {
|
|
schemaVersion: 'ecc.feedback.v1',
|
|
privacy: 'public-github',
|
|
diagnosticsUploaded: false,
|
|
routes: { ...FEEDBACK_ROUTES }
|
|
});
|
|
});
|
|
|
|
test('the payload survives a JSON round trip unchanged', () => {
|
|
const payload = getFeedbackPayload();
|
|
assert.deepEqual(JSON.parse(JSON.stringify(payload)), payload);
|
|
});
|
|
|
|
test('each payload is a fresh copy so a caller cannot alter the route table', () => {
|
|
const first = getFeedbackPayload();
|
|
const second = getFeedbackPayload();
|
|
assert.notEqual(first, second);
|
|
assert.notEqual(first.routes, second.routes);
|
|
assert.deepEqual(first, second);
|
|
|
|
first.routes.problem = 'https://example.invalid/';
|
|
first.diagnosticsUploaded = true;
|
|
assert.equal(getFeedbackPayload().routes.problem, FEEDBACK_ROUTES.problem);
|
|
assert.equal(getFeedbackPayload().diagnosticsUploaded, false);
|
|
});
|
|
|
|
test('problem report lines carry the problem route and the redaction warning', () => {
|
|
const lines = problemReportLines();
|
|
assert.equal(lines.length, 3);
|
|
assert.match(lines[0], /public GitHub issue/);
|
|
assert.equal(lines[1], FEEDBACK_ROUTES.problem);
|
|
assert.match(lines[2], /does not upload diagnostics/);
|
|
assert.match(lines[2], /Redact paths, repository names, prompts, and secrets/);
|
|
});
|
|
|
|
test('exit feedback lines carry the feedback route and promise not to block uninstall', () => {
|
|
const lines = exitFeedbackLines();
|
|
assert.equal(lines.length, 3);
|
|
assert.match(lines[0], /public GitHub issue/);
|
|
assert.equal(lines[1], FEEDBACK_ROUTES.feedback);
|
|
assert.match(lines[2], /does not upload diagnostics/);
|
|
assert.match(lines[2], /block uninstall/);
|
|
});
|
|
|
|
test('every line is a single printable line, so join("\\n") output stays well formed', () => {
|
|
for (const line of [...problemReportLines(), ...exitFeedbackLines()]) {
|
|
assert.equal(typeof line, 'string');
|
|
assert.ok(line.length > 0);
|
|
// eslint-disable-next-line no-control-regex
|
|
assert.doesNotMatch(line, /[\x00-\x1f\x7f]/);
|
|
assert.equal(line, line.trim());
|
|
}
|
|
});
|
|
|
|
test('line arrays are rebuilt per call', () => {
|
|
const lines = problemReportLines();
|
|
lines[1] = 'tampered';
|
|
assert.equal(problemReportLines()[1], FEEDBACK_ROUTES.problem);
|
|
assert.notEqual(exitFeedbackLines(), exitFeedbackLines());
|
|
});
|