Initial Commit
This commit is contained in:
132
packages/foundation/data/mime/src/charset/charset.test.ts
Normal file
132
packages/foundation/data/mime/src/charset/charset.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { sniffBom } from "./sniff-bom.js";
|
||||
import { sniffHtmlMeta } from "./sniff-html-meta.js";
|
||||
import { sniffXmlDecl } from "./sniff-xml-decl.js";
|
||||
|
||||
describe("sniffBom", () => {
|
||||
it("detects UTF-8 BOM (EF BB BF)", { timeout: 5000 }, () => {
|
||||
const bytes = new Uint8Array([0xef, 0xbb, 0xbf, 0x68, 0x65]);
|
||||
const result = sniffBom(bytes);
|
||||
expect(result?.charset).toBe("utf-8");
|
||||
expect(result?.bomLength).toBe(3);
|
||||
});
|
||||
|
||||
it("detects UTF-16 LE BOM (FF FE)", { timeout: 5000 }, () => {
|
||||
const bytes = new Uint8Array([0xff, 0xfe, 0x68, 0x00]);
|
||||
const result = sniffBom(bytes);
|
||||
expect(result?.charset).toBe("utf-16le");
|
||||
expect(result?.bomLength).toBe(2);
|
||||
});
|
||||
|
||||
it("detects UTF-16 BE BOM (FE FF)", { timeout: 5000 }, () => {
|
||||
const bytes = new Uint8Array([0xfe, 0xff, 0x00, 0x68]);
|
||||
const result = sniffBom(bytes);
|
||||
expect(result?.charset).toBe("utf-16be");
|
||||
expect(result?.bomLength).toBe(2);
|
||||
});
|
||||
|
||||
it("detects UTF-32 LE BOM (FF FE 00 00)", { timeout: 5000 }, () => {
|
||||
const bytes = new Uint8Array([0xff, 0xfe, 0x00, 0x00, 0x68]);
|
||||
const result = sniffBom(bytes);
|
||||
expect(result?.charset).toBe("utf-32le");
|
||||
expect(result?.bomLength).toBe(4);
|
||||
});
|
||||
|
||||
it("detects UTF-32 BE BOM (00 00 FE FF)", { timeout: 5000 }, () => {
|
||||
const bytes = new Uint8Array([0x00, 0x00, 0xfe, 0xff, 0x68]);
|
||||
const result = sniffBom(bytes);
|
||||
expect(result?.charset).toBe("utf-32be");
|
||||
expect(result?.bomLength).toBe(4);
|
||||
});
|
||||
|
||||
it("returns null for no BOM", { timeout: 5000 }, () => {
|
||||
const bytes = new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f]);
|
||||
expect(sniffBom(bytes)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for empty buffer", { timeout: 5000 }, () => {
|
||||
expect(sniffBom(new Uint8Array(0))).toBeNull();
|
||||
});
|
||||
|
||||
it("accepts ArrayBuffer", { timeout: 5000 }, () => {
|
||||
const buf = new Uint8Array([0xef, 0xbb, 0xbf, 0x41]).buffer;
|
||||
expect(sniffBom(buf)?.charset).toBe("utf-8");
|
||||
});
|
||||
|
||||
it("UTF-32 LE takes priority over UTF-16 LE when first 4 bytes are FF FE 00 00", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const bytes = new Uint8Array([0xff, 0xfe, 0x00, 0x00]);
|
||||
expect(sniffBom(bytes)?.charset).toBe("utf-32le");
|
||||
});
|
||||
});
|
||||
|
||||
describe("sniffHtmlMeta", () => {
|
||||
it("detects charset from <meta charset>", { timeout: 5000 }, () => {
|
||||
const html = '<html><head><meta charset="UTF-8"></head></html>';
|
||||
expect(sniffHtmlMeta(html)).toBe("utf-8");
|
||||
});
|
||||
|
||||
it("detects charset from <meta charset> without quotes", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const html = "<meta charset=UTF-8>";
|
||||
expect(sniffHtmlMeta(html)).toBe("utf-8");
|
||||
});
|
||||
|
||||
it("detects charset from http-equiv content-type", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const html =
|
||||
'<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">';
|
||||
expect(sniffHtmlMeta(html)).toBe("iso-8859-1");
|
||||
});
|
||||
|
||||
it("returns null when no charset found", { timeout: 5000 }, () => {
|
||||
expect(
|
||||
sniffHtmlMeta("<html><head><title>Hello</title></head></html>")
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("only scans first 1024 characters", { timeout: 5000 }, () => {
|
||||
const prefix = "x".repeat(1100);
|
||||
const html = `${prefix}<meta charset="UTF-8">`;
|
||||
expect(sniffHtmlMeta(html)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns lowercase charset", { timeout: 5000 }, () => {
|
||||
expect(sniffHtmlMeta('<meta charset="ISO-8859-1">')).toBe("iso-8859-1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("sniffXmlDecl", () => {
|
||||
it("detects encoding from XML declaration", { timeout: 5000 }, () => {
|
||||
const xml = '<?xml version="1.0" encoding="UTF-8"?><root/>';
|
||||
expect(sniffXmlDecl(xml)).toBe("utf-8");
|
||||
});
|
||||
|
||||
it("detects encoding with single quotes", { timeout: 5000 }, () => {
|
||||
const xml = "<?xml version='1.0' encoding='ISO-8859-1'?><root/>";
|
||||
expect(sniffXmlDecl(xml)).toBe("iso-8859-1");
|
||||
});
|
||||
|
||||
it("returns null when no encoding attribute", { timeout: 5000 }, () => {
|
||||
const xml = '<?xml version="1.0"?><root/>';
|
||||
expect(sniffXmlDecl(xml)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for non-XML content", { timeout: 5000 }, () => {
|
||||
expect(sniffXmlDecl("<html>not xml</html>")).toBeNull();
|
||||
});
|
||||
|
||||
it("only scans first 256 characters", { timeout: 5000 }, () => {
|
||||
const prefix = "x".repeat(300);
|
||||
const xml = `${prefix}<?xml version="1.0" encoding="UTF-8"?>`;
|
||||
expect(sniffXmlDecl(xml)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns lowercase encoding", { timeout: 5000 }, () => {
|
||||
const xml = '<?xml version="1.0" encoding="UTF-16"?>';
|
||||
expect(sniffXmlDecl(xml)).toBe("utf-16");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user