fix(process): normalize scenario replacements literally
capture_process_scenario declares normalization patterns as literal text, but\nreplaceAll expands \$&\, \$\`, and \$1\ in the replacement as a replacement\npattern. A caller normalizing text that contains a dollar sign silently gets\nduplicated, spliced, or dropped content in the recorded Evidence instead of\nthe requested literal replacement.\n\nUse split/join, which is literal on both sides and is already the idiom used\nfor exact-literal scenario rules in browserScenarioNormalization.ts.
This commit is contained in:
1 parent
2bf812772d
commit
f51503ef1c
2 files changed
+28
-1
No files matched your search
@@ -71,6 +71,30 @@ const scenario = (normalization: {
|
||||
},
|
||||
});
|
||||
|
||||
it("replaces caller-declared patterns literally, without expanding replacement patterns", () => {
|
||||
const declared = parseProcessScenario({
|
||||
executable: "/usr/bin/node",
|
||||
working_directory: "/workspace",
|
||||
normalization: {
|
||||
paths: false,
|
||||
time_bucket_ms: 10,
|
||||
patterns: [
|
||||
{ pattern: "8080", replacement: "$&$&" },
|
||||
{ pattern: "READY", replacement: "$$" },
|
||||
{ pattern: "NAME", replacement: "$1" },
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(
|
||||
normalizeProcessText(
|
||||
"listening on 8080; READY; NAME=alpha; tail NAME",
|
||||
declared,
|
||||
"/temporary",
|
||||
rootPid,
|
||||
),
|
||||
).toBe("listening on $&$&; $$; $1=alpha; tail $1");
|
||||
});
|
||||
|
||||
it("preserves compact JSON, counters, line numbers, and ambiguous endpoint spellings", () => {
|
||||
const input = [
|
||||
'{"pid":32,"size":108,"height":480,"width":640,"score":20}',
|
||||
|
||||
@@ -34,8 +34,11 @@ export const normalizeProcessText = (
|
||||
normalized = normalizePortTokens(normalized);
|
||||
if (scenario.normalization.pids)
|
||||
normalized = normalizePidTokens(normalized, [pid]);
|
||||
// Scenario replacements are literal text, so `$&`, `` $` ``, and `$1` must
|
||||
// reach the captured output verbatim instead of expanding as a replacement
|
||||
// pattern. split/join is literal on both sides.
|
||||
for (const pattern of scenario.normalization.patterns)
|
||||
normalized = normalized.replaceAll(pattern.pattern, pattern.replacement);
|
||||
normalized = normalized.split(pattern.pattern).join(pattern.replacement);
|
||||
return normalized;
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user