Files
claude-code-action/test/binary-detection.test.ts
T

80 lines
2.7 KiB
TypeScript

import { describe, expect, it } from "bun:test";
import { isBinaryContent } from "../src/mcp/binary-detection";
describe("isBinaryContent", () => {
describe("text content", () => {
it("treats ASCII as text", () => {
expect(isBinaryContent(Buffer.from("hello world\n"))).toBe(false);
});
it("treats multibyte UTF-8 as text", () => {
expect(isBinaryContent(Buffer.from("café — 日本語 🎉\n"))).toBe(false);
});
it("treats an empty file as text", () => {
expect(isBinaryContent(Buffer.from(""))).toBe(false);
});
it("treats CRLF and tabs as text", () => {
expect(isBinaryContent(Buffer.from("a\tb\r\nc\r\n"))).toBe(false);
});
});
describe("binary content", () => {
// The extensions below are the ones the previous allowlist covered, so
// these files were already committed correctly.
it("detects PNG", () => {
expect(
isBinaryContent(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a])),
).toBe(true);
});
// These are the regression cases: binary formats that were not on the
// allowlist and got decoded as UTF-8, corrupting the committed bytes.
it("detects BMP", () => {
expect(
isBinaryContent(Buffer.from([0x42, 0x4d, 0x36, 0x00, 0x00, 0x00])),
).toBe(true);
});
it("detects SQLite databases", () => {
expect(isBinaryContent(Buffer.from("SQLite format 3\0", "binary"))).toBe(
true,
);
});
it("detects WebAssembly modules", () => {
expect(
isBinaryContent(Buffer.from([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00])),
).toBe(true);
});
it("detects arbitrary invalid UTF-8 without NUL bytes", () => {
// Lone continuation bytes: no NUL, but not decodable as UTF-8 either.
expect(isBinaryContent(Buffer.from([0xc3, 0x28, 0xa0, 0xa1]))).toBe(true);
});
it("detects a truncated multibyte sequence", () => {
// First two bytes of a 3-byte character, cut short.
expect(isBinaryContent(Buffer.from([0xe6, 0x97]))).toBe(true);
});
});
it("round-trips text through UTF-8 without loss", () => {
const original = "acentuação, emoji 🚀, símbolos ±≠";
const buffer = Buffer.from(original);
expect(isBinaryContent(buffer)).toBe(false);
expect(buffer.toString("utf-8")).toBe(original);
});
it("preserves bytes that a UTF-8 decode would have replaced", () => {
const bytes = Buffer.from([0xff, 0xd8, 0xff, 0xe0, 0x10, 0x4a]);
expect(isBinaryContent(bytes)).toBe(true);
// What the old text path would have produced, versus base64.
expect(Buffer.from(bytes.toString("utf-8"), "utf-8")).not.toEqual(bytes);
expect(Buffer.from(bytes.toString("base64"), "base64")).toEqual(bytes);
});
});