mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(oc-path): report UTF-8 byte counts in set command output (#104496)
* fix(oc-path): report UTF-8 byte counts in set command output Use Buffer.byteLength(newBytes, 'utf8') instead of string.length for bytesWritten and dry-run byte reports. JavaScript's string.length counts UTF-16 code units which undercounts multi-byte characters when writing UTF-8 files. Co-Authored-By: Claude <noreply@anthropic.com> * test(oc-path): cover human UTF-8 dry-run count --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -169,6 +169,26 @@ describe("openclaw path CLI", () => {
|
||||
expect(readFileSync(filePath, "utf-8")).toBe(before);
|
||||
});
|
||||
|
||||
it("CLI-S02b --dry-run human output reports the rendered UTF-8 byte count", async () => {
|
||||
const filePath = join(workspaceDir, "gateway.jsonc");
|
||||
const before = '{ "version": "1.0" }';
|
||||
writeFileSync(filePath, before, "utf-8");
|
||||
const rt = createTestRuntime();
|
||||
await pathSetCommand(
|
||||
"oc://gateway.jsonc/version",
|
||||
"中文",
|
||||
{ cwd: workspaceDir, human: true, dryRun: true },
|
||||
rt,
|
||||
);
|
||||
|
||||
const [header, ...bodyLines] = stdoutText(rt).split("\n");
|
||||
const body = bodyLines.join("\n");
|
||||
expect(header).toBe(
|
||||
`--dry-run: would write ${Buffer.byteLength(body, "utf8")} bytes to ${filePath}`,
|
||||
);
|
||||
expect(readFileSync(filePath, "utf-8")).toBe(before);
|
||||
});
|
||||
|
||||
it("CLI-S05 --dry-run --diff prints a unified diff", async () => {
|
||||
const filePath = join(workspaceDir, "gateway.jsonc");
|
||||
const before = '{\n "version": "1.0",\n "enabled": true\n}\n';
|
||||
@@ -414,6 +434,29 @@ describe("openclaw path CLI", () => {
|
||||
expect(out.bytes).toBe(before);
|
||||
});
|
||||
|
||||
it("CLI-S07b reports accurate UTF-8 byte counts for multibyte set output", async () => {
|
||||
const filePath = join(workspaceDir, "gateway.jsonc");
|
||||
const before = '{\n "version": "1.0"\n}\n';
|
||||
writeFileSync(filePath, before, "utf-8");
|
||||
// Replace the whole file with CJK content via the version key.
|
||||
// CJK chars are 1 UTF-16 unit but 3 UTF-8 bytes.
|
||||
const cjkValue = "中".repeat(30);
|
||||
const rt = createTestRuntime();
|
||||
await pathSetCommand(
|
||||
"oc://gateway.jsonc/version",
|
||||
cjkValue,
|
||||
{ cwd: workspaceDir, json: true },
|
||||
rt,
|
||||
);
|
||||
expect(rt.exitCode).toBe(0);
|
||||
const out = JSON.parse(stdoutText(rt));
|
||||
// bytesWritten must match the file's actual UTF-8 byte size on disk
|
||||
const onDisk = readFileSync(filePath, "utf-8");
|
||||
expect(out.bytesWritten).toBe(Buffer.byteLength(onDisk, "utf8"));
|
||||
// bytesWritten exceeds JS string length (50 UTF-16 units < ~110 UTF-8 bytes)
|
||||
expect(out.bytesWritten).toBeGreaterThan(onDisk.length);
|
||||
});
|
||||
|
||||
it("CLI-E03 emit --cwd resolves <file> against the supplied directory", async () => {
|
||||
// Closes round-10 finding F2: emit advertises --cwd / --file in
|
||||
// the docs but the handler resolved <file> against process.cwd()
|
||||
|
||||
@@ -358,6 +358,8 @@ export async function pathSetCommand(
|
||||
return;
|
||||
}
|
||||
|
||||
const byteLength = Buffer.byteLength(newBytes, "utf8");
|
||||
|
||||
if (options.dryRun === true) {
|
||||
const diff = options.diff === true ? formatUnifiedDiff(oldBytes, newBytes, fsPath) : undefined;
|
||||
emit(
|
||||
@@ -367,7 +369,7 @@ export async function pathSetCommand(
|
||||
() =>
|
||||
diff !== undefined
|
||||
? diff || `--dry-run: no byte changes for ${fsPath}`
|
||||
: `--dry-run: would write ${newBytes.length} bytes to ${fsPath}\n${newBytes}`,
|
||||
: `--dry-run: would write ${byteLength} bytes to ${fsPath}\n${newBytes}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -375,8 +377,8 @@ export async function pathSetCommand(
|
||||
emit(
|
||||
runtime,
|
||||
mode,
|
||||
{ ok: true, dryRun: false, bytesWritten: newBytes.length, fsPath },
|
||||
() => `wrote ${newBytes.length} bytes to ${fsPath}`,
|
||||
{ ok: true, dryRun: false, bytesWritten: byteLength, fsPath },
|
||||
() => `wrote ${byteLength} bytes to ${fsPath}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user