TypeScript/src/testRunner/unittests/createMapShim.ts
Ryan Cavanaugh e00b5ecd40
Enable max-statements-per-line lint rule (#45475)
* Enable the rule

* Fix all the violations
2021-08-16 13:53:51 -07:00

327 lines
13 KiB
TypeScript

namespace ts {
describe("unittests:: createMapShim", () => {
const stringKeys = [
"1",
"3",
"2",
"4",
"0",
"999",
"A",
"B",
"C",
"Z",
"X",
"X1",
"X2",
"Y"
];
const mixedKeys = [
true,
3,
{ toString() { return "2"; } },
"4",
false,
null, // eslint-disable-line no-null/no-null
undefined,
"B",
{ toString() { return "C"; } },
"Z",
"X",
{ toString() { return "X1"; } },
"X2",
"Y"
];
function testMapIterationAddedValues<K>(keys: K[], map: ESMap<K, string>, useForEach: boolean): string {
let resultString = "";
map.set(keys[0], "1");
map.set(keys[1], "3");
map.set(keys[2], "2");
map.set(keys[3], "4");
let addedThree = false;
const doForEach = (value: string, key: K) => {
resultString += `${key}:${value};`;
// Add a new key ("0") - the map should provide this
// one in the next iteration.
if (key === keys[0]) {
map.set(keys[0], "X1");
map.set(keys[4], "X0");
map.set(keys[3], "X4");
}
else if (key === keys[1]) {
if (!addedThree) {
addedThree = true;
// Remove and re-add key "3"; the map should
// visit it after "0".
map.delete(keys[1]);
map.set(keys[1], "Y3");
// Change the value of "2"; the map should provide
// it when visiting the key.
map.set(keys[2], "Y2");
}
else {
// Check that an entry added when we visit the
// currently last entry will still be visited.
map.set(keys[5], "999");
}
}
else if (key === keys[5]) {
// Ensure that clear() behaves correctly same as removing all keys.
map.set(keys[6], "A");
map.set(keys[7], "B");
map.set(keys[8], "C");
}
else if (key === keys[6]) {
map.clear();
map.set(keys[9], "Z");
}
else if (key === keys[9]) {
// Check that the map behaves correctly when two items are
// added and removed immediately.
map.set(keys[10], "X");
map.set(keys[11], "X1");
map.set(keys[12], "X2");
map.delete(keys[11]);
map.delete(keys[12]);
map.set(keys[13], "Y");
}
};
if (useForEach) {
map.forEach(doForEach);
}
else {
// Use an iterator.
const iterator = map.entries();
while (true) {
const iterResult = iterator.next();
if (iterResult.done) {
break;
}
const [key, value] = iterResult.value;
doForEach(value, key);
}
}
return resultString;
}
let MapShim!: MapConstructor;
beforeEach(() => {
function getIterator<I extends readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined>(iterable: I): Iterator<
I extends ReadonlyESMap<infer K, infer V> ? [K, V] :
I extends ReadonlySet<infer T> ? T :
I extends readonly (infer T)[] ? T :
I extends undefined ? undefined :
never>;
function getIterator(iterable: readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined): Iterator<any> | undefined {
// override `ts.getIterator` with a version that allows us to iterate over a `MapShim` in an environment with a native `Map`.
if (iterable instanceof MapShim) return iterable.entries();
return ts.getIterator(iterable);
}
MapShim = ShimCollections.createMapShim(getIterator);
afterEach(() => {
MapShim = undefined!;
});
});
it("iterates values in insertion order and handles changes with string keys", () => {
const expectedResult = "1:1;3:3;2:Y2;4:X4;0:X0;3:Y3;999:999;A:A;Z:Z;X:X;Y:Y;";
// First, ensure the test actually has the same behavior as a native Map.
let nativeMap = new Map<string, string>();
const nativeMapForEachResult = testMapIterationAddedValues(stringKeys, nativeMap, /* useForEach */ true);
assert.equal(nativeMapForEachResult, expectedResult, "nativeMap-forEach");
nativeMap = new Map<string, string>();
const nativeMapIteratorResult = testMapIterationAddedValues(stringKeys, nativeMap, /* useForEach */ false);
assert.equal(nativeMapIteratorResult, expectedResult, "nativeMap-iterator");
// Then, test the map shim.
let localShimMap = new MapShim<string, string>();
const shimMapForEachResult = testMapIterationAddedValues(stringKeys, localShimMap, /* useForEach */ true);
assert.equal(shimMapForEachResult, expectedResult, "shimMap-forEach");
localShimMap = new MapShim<string, string>();
const shimMapIteratorResult = testMapIterationAddedValues(stringKeys, localShimMap, /* useForEach */ false);
assert.equal(shimMapIteratorResult, expectedResult, "shimMap-iterator");
});
it("iterates values in insertion order and handles changes with mixed-type keys", () => {
const expectedResult = "true:1;3:3;2:Y2;4:X4;false:X0;3:Y3;null:999;undefined:A;Z:Z;X:X;Y:Y;";
// First, ensure the test actually has the same behavior as a native Map.
let nativeMap = new Map<any, string>();
const nativeMapForEachResult = testMapIterationAddedValues(mixedKeys, nativeMap, /* useForEach */ true);
assert.equal(nativeMapForEachResult, expectedResult, "nativeMap-forEach");
nativeMap = new Map<any, string>();
const nativeMapIteratorResult = testMapIterationAddedValues(mixedKeys, nativeMap, /* useForEach */ false);
assert.equal(nativeMapIteratorResult, expectedResult, "nativeMap-iterator");
// Then, test the map shim.
let localShimMap = new MapShim<any, string>();
const shimMapForEachResult = testMapIterationAddedValues(mixedKeys, localShimMap, /* useForEach */ true);
assert.equal(shimMapForEachResult, expectedResult, "shimMap-forEach");
localShimMap = new MapShim<any, string>();
const shimMapIteratorResult = testMapIterationAddedValues(mixedKeys, localShimMap, /* useForEach */ false);
assert.equal(shimMapIteratorResult, expectedResult, "shimMap-iterator");
});
it("create from Array", () => {
const map = new MapShim([["a", "b"]]);
assert.equal(map.size, 1);
assert.isTrue(map.has("a"));
assert.equal(map.get("a"), "b");
});
it("create from Map", () => {
const map1 = new MapShim([["a", "b"]]);
const map2 = new MapShim(map1);
assert.equal(map1.size, 1);
assert.equal(map2.size, 1);
assert.isTrue(map2.has("a"));
assert.equal(map2.get("a"), "b");
});
it("set when not present", () => {
const map = new MapShim<string, string>();
const result = map.set("a", "b");
assert.equal(map.size, 1);
assert.strictEqual(result, map);
assert.isTrue(map.has("a"));
assert.equal(map.get("a"), "b");
});
it("set when present", () => {
const map = new MapShim<string, string>();
map.set("a", "z");
const result = map.set("a", "b");
assert.equal(map.size, 1);
assert.strictEqual(result, map);
assert.isTrue(map.has("a"));
assert.equal(map.get("a"), "b");
});
it("has when not present", () => {
const map = new MapShim<string, string>();
assert.isFalse(map.has("a"));
});
it("has when present", () => {
const map = new MapShim<string, string>();
map.set("a", "b");
assert.isTrue(map.has("a"));
});
it("get when not present", () => {
const map = new MapShim<string, string>();
assert.isUndefined(map.get("a"));
});
it("get when present", () => {
const map = new MapShim<string, string>();
map.set("a", "b");
assert.equal(map.get("a"), "b");
});
it("delete when not present", () => {
const map = new MapShim<string, string>();
assert.isFalse(map.delete("a"));
});
it("delete when present", () => {
const map = new MapShim<string, string>();
map.set("a", "b");
assert.isTrue(map.delete("a"));
});
it("delete twice when present", () => {
const map = new MapShim<string, string>();
map.set("a", "b");
assert.isTrue(map.delete("a"));
assert.isFalse(map.delete("a"));
});
it("remove only item and iterate", () => {
const map = new MapShim<string, string>();
map.set("a", "b");
map.delete("a");
const actual = arrayFrom(map.keys());
assert.deepEqual(actual, []);
});
it("remove first item and iterate", () => {
const map = new MapShim<string, string>();
map.set("a", "b");
map.set("c", "d");
map.delete("a");
assert.deepEqual(arrayFrom(map.keys()), ["c"]);
assert.deepEqual(arrayFrom(map.values()), ["d"]);
assert.deepEqual(arrayFrom(map.entries()), [["c", "d"]]);
});
it("remove last item and iterate", () => {
const map = new MapShim<string, string>();
map.set("a", "b");
map.set("c", "d");
map.delete("c");
assert.deepEqual(arrayFrom(map.keys()), ["a"]);
assert.deepEqual(arrayFrom(map.values()), ["b"]);
assert.deepEqual(arrayFrom(map.entries()), [["a", "b"]]);
});
it("remove middle item and iterate", () => {
const map = new MapShim<string, string>();
map.set("a", "b");
map.set("c", "d");
map.set("e", "f");
map.delete("c");
assert.deepEqual(arrayFrom(map.keys()), ["a", "e"]);
assert.deepEqual(arrayFrom(map.values()), ["b", "f"]);
assert.deepEqual(arrayFrom(map.entries()), [["a", "b"], ["e", "f"]]);
});
it("keys", () => {
const map = new MapShim<string, string>();
map.set("c", "d");
map.set("a", "b");
assert.deepEqual(arrayFrom(map.keys()), ["c", "a"]);
});
it("values", () => {
const map = new MapShim<string, string>();
map.set("c", "d");
map.set("a", "b");
assert.deepEqual(arrayFrom(map.values()), ["d", "b"]);
});
it("entries", () => {
const map = new MapShim<string, string>();
map.set("c", "d");
map.set("a", "b");
assert.deepEqual(arrayFrom(map.entries()), [["c", "d"], ["a", "b"]]);
});
it("forEach", () => {
const map = new MapShim<string, string>();
map.set("c", "d");
map.set("a", "b");
const actual: [string, string][] = [];
map.forEach((value, key) => actual.push([key, value]));
assert.deepEqual(actual, [["c", "d"], ["a", "b"]]);
});
});
}