Files
openclaw/scripts/e2e/lib/text-file-utils.mjs
2026-06-16 06:43:01 +02:00

73 lines
1.8 KiB
JavaScript

// Text file tail helpers for E2E assertions.
import fs from "node:fs";
export function tailText(text, maxBytes) {
if (Buffer.byteLength(text, "utf8") <= maxBytes) {
return text;
}
return Buffer.from(text, "utf8").subarray(-maxBytes).toString("utf8");
}
export function readTextFileTail(file, maxBytes) {
let stat;
try {
stat = fs.statSync(file);
} catch {
return "";
}
if (!stat.isFile() || stat.size <= 0) {
return "";
}
const length = Math.min(maxBytes, stat.size);
const start = stat.size - length;
let fd;
try {
fd = fs.openSync(file, "r");
const buffer = Buffer.alloc(length);
const bytesRead = fs.readSync(fd, buffer, 0, length, start);
return buffer.subarray(0, bytesRead).toString("utf8");
} catch {
return "";
} finally {
if (fd !== undefined) {
try {
fs.closeSync(fd);
} catch {
// Tail diagnostics are best-effort; callers may be preserving a richer error.
}
}
}
}
function textFileTooLargeError(message) {
return Object.assign(new Error(message), { code: "ETOOBIG" });
}
export function readTextFileBounded(file, label, maxBytes, options = {}) {
const tailBytes = options.tailBytes ?? 16 * 1024;
const stat = fs.statSync(file);
if (!stat.isFile()) {
throw new Error(`${label} is not a file: ${file}`);
}
if (stat.size > maxBytes) {
throw textFileTooLargeError(
`${label} exceeded ${maxBytes} bytes: ${file} (${stat.size} bytes). Tail: ${readTextFileTail(
file,
tailBytes,
)}`,
);
}
const text = fs.readFileSync(file, "utf8");
const bytes = Buffer.byteLength(text, "utf8");
if (bytes > maxBytes) {
throw textFileTooLargeError(
`${label} exceeded ${maxBytes} bytes: ${file} (${bytes} bytes). Tail: ${readTextFileTail(
file,
tailBytes,
)}`,
);
}
return text;
}