mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 02:48:50 +00:00
410 lines
14 KiB
TypeScript
410 lines
14 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { bunExe } from "harness";
|
|
import { MIMEParams, MIMEType } from "util";
|
|
|
|
describe("MIME API", () => {
|
|
const WHITESPACES = "\t\n\f\r ";
|
|
const NOT_HTTP_TOKEN_CODE_POINT = ",";
|
|
const NOT_HTTP_QUOTED_STRING_CODE_POINT = "\n";
|
|
|
|
test("class instance integrity", () => {
|
|
const mime = new MIMEType("application/ecmascript; ");
|
|
const mime_descriptors = Object.getOwnPropertyDescriptors(mime);
|
|
const mime_proto = Object.getPrototypeOf(mime);
|
|
const mime_impersonator = { __proto__: mime_proto };
|
|
|
|
for (const key of Object.keys(mime_descriptors)) {
|
|
const descriptor = mime_descriptors[key];
|
|
if (descriptor.get) {
|
|
const getter = descriptor.get;
|
|
expect(() => getter.call(mime_impersonator)).toThrow(/invalid receiver/i);
|
|
}
|
|
if (descriptor.set) {
|
|
const setter = descriptor.set;
|
|
expect(() => setter.call(mime_impersonator, "x")).toThrow(/invalid receiver/i);
|
|
}
|
|
}
|
|
});
|
|
|
|
test("basic properties and string conversion", () => {
|
|
const mime = new MIMEType("application/ecmascript; ");
|
|
|
|
expect(JSON.stringify(mime)).toBe(JSON.stringify("application/ecmascript"));
|
|
expect(`${mime}`).toBe("application/ecmascript");
|
|
expect(mime.essence).toBe("application/ecmascript");
|
|
expect(mime.type).toBe("application");
|
|
expect(mime.subtype).toBe("ecmascript");
|
|
expect(mime.params).toBeDefined();
|
|
expect([...mime.params]).toEqual([]);
|
|
expect(mime.params.has("not found")).toBe(false);
|
|
expect(mime.params.get("not found")).toBe(null);
|
|
expect(mime.params.delete("not found")).toBe(undefined);
|
|
});
|
|
|
|
test("type property manipulation", () => {
|
|
const mime = new MIMEType("application/ecmascript; ");
|
|
|
|
mime.type = "text";
|
|
expect(mime.type).toBe("text");
|
|
expect(JSON.stringify(mime)).toBe(JSON.stringify("text/ecmascript"));
|
|
expect(`${mime}`).toBe("text/ecmascript");
|
|
expect(mime.essence).toBe("text/ecmascript");
|
|
|
|
expect(() => {
|
|
mime.type = `${WHITESPACES}text`;
|
|
}).toThrow(/The MIME syntax for a type in/);
|
|
|
|
expect(() => {
|
|
mime.type = "";
|
|
}).toThrow(/type/i);
|
|
expect(() => {
|
|
mime.type = "/";
|
|
}).toThrow(/type/i);
|
|
expect(() => {
|
|
mime.type = "x/";
|
|
}).toThrow(/type/i);
|
|
expect(() => {
|
|
mime.type = "/x";
|
|
}).toThrow(/type/i);
|
|
expect(() => {
|
|
mime.type = NOT_HTTP_TOKEN_CODE_POINT;
|
|
}).toThrow(/type/i);
|
|
expect(() => {
|
|
mime.type = `${NOT_HTTP_TOKEN_CODE_POINT}/`;
|
|
}).toThrow(/type/i);
|
|
expect(() => {
|
|
mime.type = `/${NOT_HTTP_TOKEN_CODE_POINT}`;
|
|
}).toThrow(/type/i);
|
|
});
|
|
|
|
test("subtype property manipulation", () => {
|
|
const mime = new MIMEType("application/ecmascript; ");
|
|
mime.type = "text";
|
|
|
|
mime.subtype = "javascript";
|
|
expect(mime.type).toBe("text");
|
|
expect(JSON.stringify(mime)).toBe(JSON.stringify("text/javascript"));
|
|
expect(`${mime}`).toBe("text/javascript");
|
|
expect(mime.essence).toBe("text/javascript");
|
|
expect(`${mime.params}`).toBe("");
|
|
expect(`${new MIMEParams()}`).toBe("");
|
|
// @ts-expect-error
|
|
expect(`${new MIMEParams(mime.params)}`).toBe("");
|
|
// @ts-expect-error
|
|
expect(`${new MIMEParams(`${mime.params}`)}`).toBe("");
|
|
|
|
expect(() => {
|
|
mime.subtype = `javascript${WHITESPACES}`;
|
|
}).toThrow(/The MIME syntax for a subtype in/);
|
|
|
|
expect(() => {
|
|
mime.subtype = "";
|
|
}).toThrow(/subtype/i);
|
|
expect(() => {
|
|
mime.subtype = ";";
|
|
}).toThrow(/subtype/i);
|
|
expect(() => {
|
|
mime.subtype = "x;";
|
|
}).toThrow(/subtype/i);
|
|
expect(() => {
|
|
mime.subtype = ";x";
|
|
}).toThrow(/subtype/i);
|
|
expect(() => {
|
|
mime.subtype = NOT_HTTP_TOKEN_CODE_POINT;
|
|
}).toThrow(/subtype/i);
|
|
expect(() => {
|
|
mime.subtype = `${NOT_HTTP_TOKEN_CODE_POINT};`;
|
|
}).toThrow(/subtype/i);
|
|
expect(() => {
|
|
mime.subtype = `;${NOT_HTTP_TOKEN_CODE_POINT}`;
|
|
}).toThrow(/subtype/i);
|
|
});
|
|
|
|
test("parameters manipulation", () => {
|
|
const mime = new MIMEType("application/ecmascript; ");
|
|
mime.type = "text";
|
|
mime.subtype = "javascript";
|
|
|
|
const params = mime.params;
|
|
|
|
// Setting parameters
|
|
params.set("charset", "utf-8");
|
|
expect(params.has("charset")).toBe(true);
|
|
expect(params.get("charset")).toBe("utf-8");
|
|
expect([...params]).toEqual([["charset", "utf-8"]]);
|
|
expect(JSON.stringify(mime)).toBe(JSON.stringify("text/javascript;charset=utf-8"));
|
|
expect(`${mime}`).toBe("text/javascript;charset=utf-8");
|
|
expect(mime.essence).toBe("text/javascript");
|
|
expect(`${mime.params}`).toBe("charset=utf-8");
|
|
// @ts-expect-error
|
|
expect(`${new MIMEParams(mime.params)}`).toBe("");
|
|
// @ts-expect-error
|
|
expect(`${new MIMEParams(`${mime.params}`)}`).toBe("");
|
|
|
|
// Multiple parameters
|
|
params.set("goal", "module");
|
|
expect(params.has("goal")).toBe(true);
|
|
expect(params.get("goal")).toBe("module");
|
|
expect([...params]).toEqual([
|
|
["charset", "utf-8"],
|
|
["goal", "module"],
|
|
]);
|
|
expect(JSON.stringify(mime)).toBe(JSON.stringify("text/javascript;charset=utf-8;goal=module"));
|
|
expect(`${mime}`).toBe("text/javascript;charset=utf-8;goal=module");
|
|
expect(mime.essence).toBe("text/javascript");
|
|
expect(`${mime.params}`).toBe("charset=utf-8;goal=module");
|
|
|
|
// Invalid parameter name
|
|
expect(() => {
|
|
params.set(`${WHITESPACES}goal`, "module");
|
|
}).toThrow(/The MIME syntax for a parameter name in/);
|
|
|
|
// Updating a parameter
|
|
params.set("charset", "iso-8859-1");
|
|
expect(params.has("charset")).toBe(true);
|
|
expect(params.get("charset")).toBe("iso-8859-1");
|
|
expect([...params]).toEqual([
|
|
["charset", "iso-8859-1"],
|
|
["goal", "module"],
|
|
]);
|
|
expect(JSON.stringify(mime)).toBe(JSON.stringify("text/javascript;charset=iso-8859-1;goal=module"));
|
|
expect(`${mime}`).toBe("text/javascript;charset=iso-8859-1;goal=module");
|
|
expect(mime.essence).toBe("text/javascript");
|
|
|
|
// Deleting a parameter
|
|
params.delete("charset");
|
|
expect(params.has("charset")).toBe(false);
|
|
expect(params.get("charset")).toBe(null);
|
|
expect([...params]).toEqual([["goal", "module"]]);
|
|
expect(JSON.stringify(mime)).toBe(JSON.stringify("text/javascript;goal=module"));
|
|
expect(`${mime}`).toBe("text/javascript;goal=module");
|
|
expect(mime.essence).toBe("text/javascript");
|
|
|
|
// Empty parameter value
|
|
params.set("x", "");
|
|
expect(params.has("x")).toBe(true);
|
|
expect(params.get("x")).toBe("");
|
|
expect([...params]).toEqual([
|
|
["goal", "module"],
|
|
["x", ""],
|
|
]);
|
|
expect(JSON.stringify(mime)).toBe(JSON.stringify('text/javascript;goal=module;x=""'));
|
|
expect(`${mime}`).toBe('text/javascript;goal=module;x=""');
|
|
expect(mime.essence).toBe("text/javascript");
|
|
});
|
|
|
|
test("invalid parameter names", () => {
|
|
const mime = new MIMEType("text/javascript");
|
|
const params = mime.params;
|
|
|
|
expect(() => params.set("", "x")).toThrow(/parameter name/i);
|
|
expect(() => params.set("=", "x")).toThrow(/parameter name/i);
|
|
expect(() => params.set("x=", "x")).toThrow(/parameter name/i);
|
|
expect(() => params.set("=x", "x")).toThrow(/parameter name/i);
|
|
expect(() => params.set(`${NOT_HTTP_TOKEN_CODE_POINT}=`, "x")).toThrow(/parameter name/i);
|
|
expect(() => params.set(`${NOT_HTTP_TOKEN_CODE_POINT}x`, "x")).toThrow(/parameter name/i);
|
|
expect(() => params.set(`x${NOT_HTTP_TOKEN_CODE_POINT}`, "x")).toThrow(/parameter name/i);
|
|
});
|
|
|
|
test("invalid parameter values", () => {
|
|
const mime = new MIMEType("text/javascript");
|
|
const params = mime.params;
|
|
|
|
expect(() => params.set("x", `${NOT_HTTP_QUOTED_STRING_CODE_POINT};`)).toThrow(/parameter value/i);
|
|
expect(() => params.set("x", `${NOT_HTTP_QUOTED_STRING_CODE_POINT}x`)).toThrow(/parameter value/i);
|
|
expect(() => params.set("x", `x${NOT_HTTP_QUOTED_STRING_CODE_POINT}`)).toThrow(/parameter value/i);
|
|
});
|
|
});
|
|
|
|
test("Exact match with node", () => {
|
|
const result = Bun.spawnSync({
|
|
cmd: [bunExe(), import.meta.dir + "/exact/mime-test.js"],
|
|
});
|
|
|
|
expect(result.stderr.toString("utf-8")).toBe("");
|
|
expect(result.exitCode).toBe(0);
|
|
// exact output on v23.4.0
|
|
expect(result.stdout.toString("utf-8")).toMatchInlineSnapshot(`
|
|
"=== BASIC PROPERTIES AND STRING CONVERSION ===
|
|
mime1: application/ecmascript
|
|
JSON.stringify: "application/ecmascript"
|
|
essence: application/ecmascript
|
|
type: application
|
|
subtype: ecmascript
|
|
params empty: true
|
|
params.has("not found"): false
|
|
params.get("not found"): true
|
|
|
|
=== TYPE PROPERTY MANIPULATION ===
|
|
Original: application/javascript
|
|
After type change: text/javascript
|
|
essence: text/javascript
|
|
Error on empty type as expected
|
|
Error on invalid type as expected
|
|
|
|
=== SUBTYPE PROPERTY MANIPULATION ===
|
|
Original: text/plain
|
|
After subtype change: text/javascript
|
|
Error on empty subtype as expected
|
|
Error on invalid subtype as expected
|
|
|
|
=== PARAMETERS MANIPULATION ===
|
|
params.has("charset"): true
|
|
params.get("charset"): utf-8
|
|
params entries length: 1
|
|
mime with charset: text/javascript;charset=utf-8
|
|
params.has("goal"): true
|
|
params.get("goal"): module
|
|
params entries length: 2
|
|
mime with multiple params: text/javascript;charset=utf-8;goal=module
|
|
updated charset: iso-8859-1
|
|
mime with updated charset: text/javascript;charset=iso-8859-1;goal=module
|
|
params.has("charset") after delete: false
|
|
params.get("charset") after delete: true
|
|
params entries length after delete: 1
|
|
mime after param delete: text/javascript;goal=module
|
|
params.has("x"): true
|
|
params.get("x"): empty string
|
|
mime with empty param: text/javascript;goal=module;x=""
|
|
|
|
=== PARAMETER CASE SENSITIVITY ===
|
|
mime5: text/javascript;charset=UTF-8
|
|
mime5.params.get("CHARSET"): true
|
|
mime5.params.get("charset"): UTF-8
|
|
mime5.params.has("CHARSET"): false
|
|
mime5.params.has("charset"): true
|
|
mime5.params.has("abc"): false
|
|
mime5.params.has("def"): false
|
|
mime5.params.get("CHARSET") after set: UTF-8
|
|
mime5.params.has("CHARSET") after set: true
|
|
|
|
=== QUOTED PARAMETER VALUES ===
|
|
mime6: text/plain;charset=utf-8
|
|
mime6.params.get("charset"): utf-8
|
|
mime with filename: text/javascript;goal=module;x="";filename="file with spaces.txt"
|
|
|
|
=== INVALID PARAMETERS ===
|
|
Error on empty param name as expected
|
|
Error on invalid param name as expected
|
|
Error on invalid param value as expected
|
|
|
|
=== PARAMS ITERATION ===
|
|
Iterating params.entries():
|
|
charset: utf-8
|
|
format: flowed
|
|
Iterating params.keys():
|
|
charset
|
|
format
|
|
Iterating params.values():
|
|
utf-8
|
|
flowed
|
|
Iterating params directly:
|
|
charset: utf-8
|
|
format: flowed
|
|
|
|
=== PARSING EDGE CASES ===
|
|
mime8: text/plain;charset=utf-8;goal=module
|
|
Has empty param: false
|
|
mime9: text/plain;charset=utf-8
|
|
mime9 charset: utf-8
|
|
|
|
=== TO STRING AND TO JSON ===
|
|
toString(): text/plain;charset=utf-8
|
|
toJSON(): text/plain;charset=utf-8
|
|
params toString(): charset=utf-8
|
|
params toJSON(): charset=utf-8
|
|
=== BASIC MIMEPARAMS OPERATIONS ===
|
|
New params empty: true
|
|
params.has("charset"): true
|
|
params.get("charset"): utf-8
|
|
params entries length: 1
|
|
params toString(): charset=utf-8
|
|
|
|
=== CASE SENSITIVITY ===
|
|
params.has("CHARSET"): false
|
|
params.get("CHARSET"): true
|
|
After setting CHARSET, params.has("CHARSET"): true
|
|
After setting CHARSET, params.get("CHARSET"): iso-8859-1
|
|
params.has("charset"): true
|
|
params.get("charset"): utf-8
|
|
params entries length: 2
|
|
params toString(): charset=utf-8;CHARSET=iso-8859-1
|
|
|
|
=== DELETE OPERATION ===
|
|
After delete, params.has("charset"): false
|
|
After delete, params.get("charset"): true
|
|
params.has("CHARSET"): true
|
|
params entries length: 1
|
|
params toString(): CHARSET=iso-8859-1
|
|
|
|
=== MULTIPLE PARAMETERS ===
|
|
params entries length: 3
|
|
params toString(): CHARSET=iso-8859-1;format=flowed;delsp=yes
|
|
|
|
=== QUOTED VALUES ===
|
|
params.get("filename"): file with spaces.txt
|
|
params toString(): CHARSET=iso-8859-1;format=flowed;delsp=yes;filename="file with spaces.txt"
|
|
|
|
=== EMPTY VALUES ===
|
|
params.has("empty"): true
|
|
params.get("empty"): empty string
|
|
params toString() with empty value: CHARSET=iso-8859-1;format=flowed;delsp=yes;filename="file with spaces.txt";empty=""
|
|
|
|
=== ESCAPE SEQUENCES IN QUOTED VALUES ===
|
|
params.get("path"): C:\\Program Files\\App
|
|
params toString() with backslashes: CHARSET=iso-8859-1;format=flowed;delsp=yes;filename="file with spaces.txt";empty="";path="C:\\\\Program Files\\\\App"
|
|
|
|
=== SPECIAL CHARACTERS ===
|
|
params.get("test"): !#$%&'*+-.^_\`|~
|
|
params toString() with special chars: CHARSET=iso-8859-1;format=flowed;delsp=yes;filename="file with spaces.txt";empty="";path="C:\\\\Program Files\\\\App";test=!#$%&'*+-.^_\`|~
|
|
|
|
=== ERROR CASES ===
|
|
Empty name error: TypeError
|
|
Invalid name error: TypeError
|
|
Invalid value error: TypeError
|
|
|
|
=== ITERATION METHODS ===
|
|
Keys:
|
|
CHARSET
|
|
format
|
|
delsp
|
|
filename
|
|
empty
|
|
path
|
|
test
|
|
Values:
|
|
iso-8859-1
|
|
flowed
|
|
yes
|
|
file with spaces.txt
|
|
|
|
C:\\Program Files\\App
|
|
!#$%&'*+-.^_\`|~
|
|
Entries:
|
|
CHARSET: iso-8859-1
|
|
format: flowed
|
|
delsp: yes
|
|
filename: file with spaces.txt
|
|
empty:
|
|
path: C:\\Program Files\\App
|
|
test: !#$%&'*+-.^_\`|~
|
|
Direct iteration:
|
|
CHARSET: iso-8859-1
|
|
format: flowed
|
|
delsp: yes
|
|
filename: file with spaces.txt
|
|
empty:
|
|
path: C:\\Program Files\\App
|
|
test: !#$%&'*+-.^_\`|~
|
|
|
|
=== JSON SERIALIZATION ===
|
|
params.toJSON(): CHARSET=iso-8859-1;format=flowed;delsp=yes;filename="file with spaces.txt";empty="";path="C:\\\\Program Files\\\\App";test=!#$%&'*+-.^_\`|~
|
|
JSON.stringify(params): "CHARSET=iso-8859-1;format=flowed;delsp=yes;filename=\\"file with spaces.txt\\";empty=\\"\\";path=\\"C:\\\\\\\\Program Files\\\\\\\\App\\";test=!#$%&'*+-.^_\`|~"
|
|
|
|
=== CLONE AND MODIFY ===
|
|
Original params: charset=utf-8;boundary=boundary
|
|
Cloned params: charset=iso-8859-1;boundary=boundary
|
|
"
|
|
`);
|
|
});
|