be755dd8eb
Code-review fixes: guard pathToFileURL against undefined argv[1]; reject unrecognised flags with exit 2 before any filesystem access (prevents a --revert typo from silently applying the patch). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { execFileSync } from 'node:child_process';
|
|
import {
|
|
isPatched, applyPatch, revertPatch, resolveTargetPath, PATCH_MARKER,
|
|
} from './ruflo-h7-patch.mjs';
|
|
|
|
// Фикстура — фактический getBridge() из memory-initializer.js:70-84.
|
|
const FIXTURE = `let _bridge;
|
|
async function getBridge() {
|
|
if (_bridge === null)
|
|
return null;
|
|
if (_bridge)
|
|
return _bridge;
|
|
try {
|
|
_bridge = await import('./memory-bridge.js');
|
|
return _bridge;
|
|
}
|
|
catch {
|
|
_bridge = null;
|
|
return null;
|
|
}
|
|
}
|
|
`;
|
|
|
|
test('isPatched: false on clean content', () => {
|
|
assert.equal(isPatched(FIXTURE), false);
|
|
});
|
|
|
|
test('applyPatch: inserts patch line right after the anchor', () => {
|
|
const { content, changed } = applyPatch(FIXTURE);
|
|
assert.equal(changed, true);
|
|
assert.ok(content.includes(PATCH_MARKER));
|
|
const lines = content.split('\n');
|
|
const anchorIdx = lines.findIndex((l) => l.includes('async function getBridge()'));
|
|
assert.ok(lines[anchorIdx + 1].includes(PATCH_MARKER));
|
|
});
|
|
|
|
test('applyPatch: idempotent — second apply is a no-op', () => {
|
|
const once = applyPatch(FIXTURE).content;
|
|
const twice = applyPatch(once);
|
|
assert.equal(twice.changed, false);
|
|
assert.equal(twice.content, once);
|
|
});
|
|
|
|
test('isPatched: true after applyPatch', () => {
|
|
assert.equal(isPatched(applyPatch(FIXTURE).content), true);
|
|
});
|
|
|
|
test('applyPatch: throws when the anchor is absent', () => {
|
|
assert.throws(() => applyPatch('function other() {}\n'), /anchor .* not found/);
|
|
});
|
|
|
|
test('revertPatch: removes the patch line and restores the original', () => {
|
|
const patched = applyPatch(FIXTURE).content;
|
|
const { content, changed } = revertPatch(patched);
|
|
assert.equal(changed, true);
|
|
assert.equal(isPatched(content), false);
|
|
assert.equal(content, FIXTURE);
|
|
});
|
|
|
|
test('revertPatch: no-op on unpatched content', () => {
|
|
assert.equal(revertPatch(FIXTURE).changed, false);
|
|
});
|
|
|
|
test('resolveTargetPath: null when no candidate file exists', () => {
|
|
assert.equal(resolveTargetPath('/nonexistent/npm/root/zzz'), null);
|
|
});
|
|
|
|
test('main: rejects an unknown flag with exit code 2', () => {
|
|
assert.throws(
|
|
() => execFileSync(process.execPath, ['tools/ruflo-h7-patch.mjs', '--bogus'], { stdio: 'pipe' }),
|
|
(err) => err.status === 2,
|
|
);
|
|
});
|