std/msgpack/encode_test.ts
lionel-rowe 15fc72c273
fix(msgpack): accept readonly input data in encode() (#5832)
feat(msgpack): accept readonly input data (#5831)
2024-08-27 15:16:03 +10:00

229 lines
6.3 KiB
TypeScript

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertEquals, assertThrows } from "@std/assert";
import * as path from "@std/path";
import { decode, encode } from "./mod.ts";
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
const testdataDir = path.resolve(moduleDir, "testdata");
Deno.test("encode() handles testdata", () => {
const one = JSON.parse(
Deno.readTextFileSync(path.join(testdataDir, "1.json")),
);
assertEquals(decode(encode(one)), one);
const two = JSON.parse(
Deno.readTextFileSync(path.join(testdataDir, "2.json")),
);
assertEquals(decode(encode(two)), two);
const three = JSON.parse(
Deno.readTextFileSync(path.join(testdataDir, "3.json")),
);
assertEquals(decode(encode(three)), three);
const four = JSON.parse(
Deno.readTextFileSync(path.join(testdataDir, "4.json")),
);
assertEquals(decode(encode(four)), four);
const five = JSON.parse(
Deno.readTextFileSync(path.join(testdataDir, "5.json")),
);
assertEquals(decode(encode(five)), five);
});
Deno.test("encode() handles positive numbers", () => {
assertEquals(encode(1), Uint8Array.of(1));
assertEquals(decode(encode(1)), 1);
assertEquals(encode(255), Uint8Array.of(0xcc, 255));
assertEquals(decode(encode(255)), 255);
assertEquals(encode(2000), Uint8Array.of(0xcd, 7, 208));
assertEquals(decode(encode(2000)), 2000);
assertEquals(encode(70000), Uint8Array.of(0xce, 0, 1, 17, 112));
assertEquals(decode(encode(70000)), 70000);
assertEquals(
encode(20000000000),
Uint8Array.of(0xcb, 66, 18, 160, 95, 32, 0, 0, 0),
);
assertEquals(decode(encode(20000000000)), 20000000000);
});
Deno.test("encode() handles negative numbers", () => {
assertEquals(encode(-1), Uint8Array.of(255));
assertEquals(decode(encode(-1)), -1);
assertEquals(encode(-127), Uint8Array.of(0xd0, 129));
assertEquals(decode(encode(-127)), -127);
assertEquals(encode(-1000), Uint8Array.of(0xd1, 252, 24));
assertEquals(decode(encode(-1000)), -1000);
assertEquals(encode(-60000), Uint8Array.of(0xd2, 255, 255, 21, 160));
assertEquals(decode(encode(-60000)), -60000);
assertEquals(
encode(-600000000000),
Uint8Array.of(0xcb, 194, 97, 118, 89, 46, 0, 0, 0),
);
assertEquals(decode(encode(-600000000000)), -600000000000);
});
Deno.test("encode() handles floats", () => {
assertEquals(
encode(0.3),
Uint8Array.of(0xcb, 63, 211, 51, 51, 51, 51, 51, 51),
);
assertEquals(decode(encode(0.3)), 0.3);
});
Deno.test("encode() handles bigints", () => {
assertEquals(encode(0n), Uint8Array.of(0xcf, 0, 0, 0, 0, 0, 0, 0, 0));
assertEquals(decode(encode(0n)), 0n);
assertEquals(
encode(-10n),
Uint8Array.of(0xd3, 255, 255, 255, 255, 255, 255, 255, 246),
);
assertEquals(decode(encode(-10n)), -10n);
assertEquals(encode(10n), Uint8Array.of(0xcf, 0, 0, 0, 0, 0, 0, 0, 10));
assertEquals(decode(encode(10n)), 10n);
assertEquals(
encode(9999999999999999999n),
Uint8Array.of(0xcf, 138, 199, 35, 4, 137, 231, 255, 255),
);
assertEquals(decode(encode(9999999999999999999n)), 9999999999999999999n);
assertThrows(() => encode(99999999999999999999999n));
assertThrows(() => encode(-99999999999999999999999n));
});
Deno.test("encode() handles strings", () => {
assertEquals(
encode("hello world"),
Uint8Array.of(171, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100),
);
assertEquals(decode(encode("hello world")), "hello world");
const mediumString = "a".repeat(255);
assertEquals(
encode(mediumString),
Uint8Array.of(0xd9, 255, ...new Array(mediumString.length).fill(97)),
);
assertEquals(decode(encode(mediumString)), mediumString);
const longString = "a".repeat(256);
assertEquals(
encode(longString),
Uint8Array.of(0xda, 1, 0, ...new Array(longString.length).fill(97)),
);
assertEquals(decode(encode(longString)), longString);
const reallyLongString = "a".repeat(65536);
assertEquals(
encode(reallyLongString),
Uint8Array.of(
0xdb,
0,
1,
0,
0,
...new Array(reallyLongString.length).fill(97),
),
);
assertEquals(decode(encode(reallyLongString)), reallyLongString);
});
Deno.test("encode() handles Uint8Arrays", () => {
assertEquals(
encode(Uint8Array.of(0, 1, 2, 3)),
Uint8Array.of(0xc4, 4, 0, 1, 2, 3),
);
assertEquals(
encode(new Uint8Array(256)),
Uint8Array.of(0xc5, 1, 0, ...new Uint8Array(256)),
);
assertEquals(
encode(new Uint8Array(65536)),
Uint8Array.of(0xc6, 0, 1, 0, 0, ...new Uint8Array(65536)),
);
});
Deno.test("encode() handles arrays", () => {
const arr0: never[] = [];
assertEquals(decode(encode(arr0)), arr0);
const arr1 = [1, 2, 3, 4, 5, 6];
assertEquals(decode(encode(arr1)), arr1);
const arr2 = new Array(256).fill(0);
assertEquals(decode(encode(arr2)), arr2);
const nestedArr = [[1, 2, 3], [1, 2], 5];
assertEquals(decode(encode(nestedArr)), nestedArr);
});
Deno.test("encode() handles maps", () => {
const map0 = {};
assertEquals(decode(encode(map0)), map0);
const mapNull = Object.create(null);
assertEquals(decode(encode(mapNull)), mapNull);
const map1 = { "a": 0, "b": 2, "c": "three", "d": null };
assertEquals(decode(encode(map1)), map1);
const nestedMap = { "a": -1, "b": 2, "c": "three", "d": null, "e": map1 };
assertEquals(decode(encode(nestedMap)), nestedMap);
});
Deno.test("encode() handles huge array with 100k objects", () => {
const bigArray = [];
for (let i = 0; i < 100000; i++) {
bigArray.push({ a: { i: `${i}` }, i: i });
}
const bigObject = { a: bigArray };
assertEquals(decode(encode(bigObject)), bigObject);
});
Deno.test("encode() handles huge object with 100k properties", () => {
const bigObject = {};
for (let i = 0; i < 100000; i++) {
const _ = Object.defineProperty(bigObject, `prop_${i}`, {
value: i,
enumerable: true,
});
}
assertEquals(decode(encode(bigObject)), bigObject);
});
Deno.test("encode() throws when the object is an instance of a custom class", () => {
class Foo {
a = 1;
}
// deno-lint-ignore no-explicit-any
const foo = new Foo() as any;
assertThrows(
() => encode(foo),
Error,
"Cannot safely encode value into messagepack",
);
});
Deno.test("encode() accepts `as const` data", () => {
const data = {
a: 1,
b: { c: 2 },
d: [3, { e: 4 }],
} as const;
void (() => {
encode(data);
});
});