214 lines
5.9 KiB
TypeScript
214 lines
5.9 KiB
TypeScript
import {
|
|
describe,
|
|
expect,
|
|
it,
|
|
mock,
|
|
} from "https://code.thunderk.net/typescript/devtools/raw/1.3.0/testing.ts";
|
|
import { Serializer } from "./serializer.ts";
|
|
|
|
class TestSerializerObj1 {
|
|
a: number;
|
|
constructor(a = 0) {
|
|
this.a = a;
|
|
}
|
|
}
|
|
|
|
class TestSerializerObj2 {
|
|
a = () => 1;
|
|
b = [(obj: any) => 2];
|
|
}
|
|
|
|
class TestSerializerObj3 {
|
|
a = [1, 2];
|
|
postUnserialize() {
|
|
this.a.push(3);
|
|
}
|
|
}
|
|
|
|
class TestSerializerObj4 extends TestSerializerObj1 {
|
|
}
|
|
|
|
const TEST_NS = {
|
|
TestSerializerObj1,
|
|
TestSerializerObj2,
|
|
TestSerializerObj3,
|
|
};
|
|
|
|
const TEST_NS_FLAT = [
|
|
TestSerializerObj1,
|
|
TestSerializerObj2,
|
|
TestSerializerObj3,
|
|
];
|
|
|
|
const TEST_NS_RENAME = {
|
|
ob1: TestSerializerObj1,
|
|
ob2: TestSerializerObj2,
|
|
ob3: TestSerializerObj3,
|
|
};
|
|
|
|
function checkReversability(
|
|
obj: any,
|
|
namespace: any = TEST_NS,
|
|
equality?: (loaded: any, orig: any) => void,
|
|
): any {
|
|
var serializer = new Serializer(namespace);
|
|
var data = serializer.serialize(obj);
|
|
serializer = new Serializer(namespace);
|
|
var loaded = serializer.unserialize(data);
|
|
if (equality) {
|
|
equality(loaded, obj);
|
|
} else {
|
|
expect(loaded).toEqual(obj);
|
|
}
|
|
return loaded;
|
|
}
|
|
|
|
describe(Serializer, () => {
|
|
it("serializes simple objects", () => {
|
|
var obj = {
|
|
"a": 5,
|
|
"b": null,
|
|
"c": [{ "a": 2 }, "test"],
|
|
"d": new Set([1, 4]),
|
|
"e": new Map([["z", 8], ["t", 2]]),
|
|
};
|
|
const result = checkReversability(obj);
|
|
expect(result["a"]).toBe(5);
|
|
expect(result["b"]).toBe(null);
|
|
expect(result["c"][0]["a"]).toBe(2);
|
|
expect(result["d"].has(1)).toBe(true);
|
|
expect(result["d"].has(2)).toBe(false);
|
|
expect(result["e"].get("z")).toBe(8);
|
|
expect(result["e"].get("k")).toBeUndefined();
|
|
|
|
checkReversability(new Set(["a", new Set([1, "b"])]));
|
|
checkReversability(new Map([["a", new Map([[1, "test"]])]]));
|
|
});
|
|
|
|
it("restores objects constructed from class", () => {
|
|
let loaded = checkReversability(new TestSerializerObj1(5));
|
|
expect(loaded.a).toBe(5);
|
|
expect(loaded).toBeInstanceOf(TestSerializerObj1);
|
|
|
|
loaded = checkReversability(new TestSerializerObj1(5), TEST_NS_FLAT);
|
|
expect(loaded.a).toBe(5);
|
|
expect(loaded).toBeInstanceOf(TestSerializerObj1);
|
|
|
|
loaded = checkReversability(new TestSerializerObj1(5), TEST_NS_RENAME);
|
|
expect(loaded.a).toBe(5);
|
|
expect(loaded).toBeInstanceOf(TestSerializerObj1);
|
|
});
|
|
|
|
it("serializes reference to class type", () => {
|
|
let loaded = checkReversability(TestSerializerObj1);
|
|
expect(loaded).toBe(TestSerializerObj1);
|
|
});
|
|
|
|
it("stores one version of the same object", () => {
|
|
var a = new TestSerializerObj1(8);
|
|
var b = new TestSerializerObj1(8);
|
|
var c = {
|
|
"r": a,
|
|
"s": ["test", a],
|
|
"t": a,
|
|
"u": b,
|
|
};
|
|
var loaded = checkReversability(c);
|
|
expect(loaded.t).toBe(loaded.r);
|
|
expect(loaded.s[1]).toBe(loaded.r);
|
|
expect(loaded.u).not.toBe(loaded.r);
|
|
});
|
|
|
|
it("handles circular references", () => {
|
|
var a: any = { b: {} };
|
|
a.b.c = a;
|
|
|
|
checkReversability(a, undefined, (loaded) => {
|
|
expect(Object.keys(loaded)).toEqual(["b"]);
|
|
expect(Object.keys(loaded.b)).toEqual(["c"]);
|
|
expect(Object.keys(loaded.b.c)).toEqual(["b"]);
|
|
expect(Object.keys(loaded.b.c.b)).toEqual(["c"]);
|
|
expect(loaded.b.c).toBe(loaded);
|
|
expect(loaded.b.c.b).toBe(loaded.b);
|
|
});
|
|
});
|
|
|
|
it("ignores some classes", () => {
|
|
let serializer = new Serializer(TEST_NS);
|
|
serializer.addIgnoredClass("TestSerializerObj1");
|
|
|
|
let data = serializer.serialize({ a: 5, b: new TestSerializerObj1() });
|
|
let loaded = serializer.unserialize(data);
|
|
|
|
expect(loaded).toEqual({ a: 5, b: undefined });
|
|
|
|
serializer = new Serializer(TEST_NS);
|
|
serializer.addIgnoredClass(TestSerializerObj1);
|
|
|
|
data = serializer.serialize({ a: 5, b: new TestSerializerObj1() });
|
|
loaded = serializer.unserialize(data);
|
|
|
|
expect(loaded).toEqual({ a: 5, b: undefined });
|
|
|
|
serializer = new Serializer(TEST_NS_RENAME);
|
|
serializer.addIgnoredClass(TestSerializerObj1);
|
|
|
|
data = serializer.serialize({ a: 5, b: new TestSerializerObj1() });
|
|
loaded = serializer.unserialize(data);
|
|
|
|
expect(loaded).toEqual({ a: 5, b: undefined });
|
|
});
|
|
|
|
it("ignores functions", () => {
|
|
let serializer = new Serializer(TEST_NS);
|
|
let data = serializer.serialize({ obj: new TestSerializerObj2() });
|
|
let loaded = serializer.unserialize(data);
|
|
|
|
let expected: any = new TestSerializerObj2();
|
|
expected.a = undefined;
|
|
expected.b[0] = undefined;
|
|
expect(loaded).toEqual({ obj: expected });
|
|
});
|
|
|
|
it("calls specific postUnserialize", () => {
|
|
let serializer = new Serializer(TEST_NS);
|
|
let data = serializer.serialize({ obj: new TestSerializerObj3() });
|
|
let loaded = serializer.unserialize(data);
|
|
|
|
let expected = new TestSerializerObj3();
|
|
expected.a = [1, 2, 3];
|
|
expect(loaded).toEqual({ obj: expected });
|
|
});
|
|
|
|
it("handles missing classes", () => {
|
|
mock(console, "error", undefined, (mock_error) => {
|
|
let serializer = new Serializer(TEST_NS);
|
|
let data = serializer.serialize({ obj: new TestSerializerObj4() });
|
|
let loaded = serializer.unserialize(data);
|
|
expect(loaded).toEqual({ obj: { a: 0 } });
|
|
expect(mock_error).toHaveBeenCalledWith(
|
|
"Can't find class",
|
|
"TestSerializerObj4",
|
|
);
|
|
});
|
|
});
|
|
|
|
it("uses namespace alias to protect from property mangling", () => {
|
|
const data = {
|
|
a: new TestSerializerObj1(1),
|
|
b: new TestSerializerObj1(2),
|
|
c: [new TestSerializerObj1(3)],
|
|
};
|
|
|
|
const serializer1 = new Serializer(TEST_NS);
|
|
const serializer2 = new Serializer(TEST_NS_RENAME);
|
|
|
|
const dumped1 = serializer1.serialize(data);
|
|
const dumped2 = serializer2.serialize(data);
|
|
|
|
expect(dumped1.length).toBeGreaterThan(dumped2.length);
|
|
|
|
expect(serializer1.unserialize(dumped1)).toEqual(data);
|
|
expect(serializer2.unserialize(dumped2)).toEqual(data);
|
|
});
|
|
});
|