• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    describe("unittests:: createSetShim", () => {
3        const stringKeys = [
4            "1",
5            "3",
6            "2",
7            "4",
8            "0",
9            "999",
10            "A",
11            "B",
12            "C",
13            "Z",
14            "X",
15            "X1",
16            "X2",
17            "Y"
18        ];
19
20        const mixedKeys = [
21            true,
22            3,
23            { toString() { return "2"; } },
24            "4",
25            false,
26            null, // eslint-disable-line no-null/no-null
27            undefined,
28            "B",
29            { toString() { return "C"; } },
30            "Z",
31            "X",
32            { toString() { return "X1"; } },
33            "X2",
34            "Y"
35        ];
36
37        function testSetIterationAddedValues<K>(keys: K[], set: Set<K>, useForEach: boolean): string {
38            let resultString = "";
39
40            set.add(keys[0]);
41            set.add(keys[1]);
42            set.add(keys[2]);
43            set.add(keys[3]);
44
45            let addedThree = false;
46            const doForEach = (key: K) => {
47                resultString += `${key};`;
48
49                // Add a new key ("0") - the set should provide this
50                // one in the next iteration.
51                if (key === keys[0]) {
52                    set.add(keys[0]);
53                    set.add(keys[4]);
54                    set.add(keys[3]);
55                }
56                else if (key === keys[1]) {
57                    if (!addedThree) {
58                        addedThree = true;
59
60                        // Remove and re-add key "3"; the set should
61                        // visit it after "0".
62                        set.delete(keys[1]);
63                        set.add(keys[1]);
64
65                        // Change the value of "2"; the set should provide
66                        // it when visiting the key.
67                        set.add(keys[2]);
68                    }
69                    else {
70                        // Check that an entry added when we visit the
71                        // currently last entry will still be visited.
72                        set.add(keys[5]);
73                    }
74                }
75                else if (key === keys[5]) {
76                    // Ensure that clear() behaves correctly same as removing all keys.
77                    set.add(keys[6]);
78                    set.add(keys[7]);
79                    set.add(keys[8]);
80                }
81                else if (key === keys[6]) {
82                    set.clear();
83                    set.add(keys[9]);
84                }
85                else if (key === keys[9]) {
86                    // Check that the set behaves correctly when two items are
87                    // added and removed immediately.
88                    set.add(keys[10]);
89                    set.add(keys[11]);
90                    set.add(keys[12]);
91                    set.delete(keys[11]);
92                    set.delete(keys[12]);
93                    set.add(keys[13]);
94                }
95            };
96
97            if (useForEach) {
98                set.forEach(doForEach);
99            }
100            else {
101                // Use an iterator.
102                const iterator = set.values();
103                while (true) {
104                    const iterResult = iterator.next();
105                    if (iterResult.done) {
106                        break;
107                    }
108
109                    doForEach(iterResult.value);
110                }
111            }
112
113            return resultString;
114        }
115
116        let SetShim!: SetConstructor;
117        beforeEach(() => {
118            function getIterator<I extends readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined>(iterable: I): Iterator<
119                I extends ReadonlyESMap<infer K, infer V> ? [K, V] :
120                I extends ReadonlySet<infer T> ? T :
121                I extends readonly (infer T)[] ? T :
122                I extends undefined ? undefined :
123                never>;
124            function getIterator(iterable: readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined): Iterator<any> | undefined {
125                // override `ts.getIterator` with a version that allows us to iterate over a `SetShim` in an environment with a native `Set`.
126                if (iterable instanceof SetShim) return iterable.values();
127                return ts.getIterator(iterable);
128            }
129
130            SetShim = ShimCollections.createSetShim(getIterator);
131            afterEach(() => {
132                SetShim = undefined!;
133            });
134        });
135
136        it("iterates values in insertion order and handles changes with string keys", () => {
137            const expectedResult = "1;3;2;4;0;3;999;A;Z;X;Y;";
138
139            // First, ensure the test actually has the same behavior as a native Set.
140            let nativeSet = new Set<string>();
141            const nativeSetForEachResult = testSetIterationAddedValues(stringKeys, nativeSet, /* useForEach */ true);
142            assert.equal(nativeSetForEachResult, expectedResult, "nativeSet-forEach");
143
144            nativeSet = new Set<string>();
145            const nativeSetIteratorResult = testSetIterationAddedValues(stringKeys, nativeSet, /* useForEach */ false);
146            assert.equal(nativeSetIteratorResult, expectedResult, "nativeSet-iterator");
147
148            // Then, test the set shim.
149            let localShimSet = new SetShim<string>();
150            const shimSetForEachResult = testSetIterationAddedValues(stringKeys, localShimSet, /* useForEach */ true);
151            assert.equal(shimSetForEachResult, expectedResult, "shimSet-forEach");
152
153            localShimSet = new SetShim<string>();
154            const shimSetIteratorResult = testSetIterationAddedValues(stringKeys, localShimSet, /* useForEach */ false);
155            assert.equal(shimSetIteratorResult, expectedResult, "shimSet-iterator");
156        });
157
158        it("iterates values in insertion order and handles changes with mixed-type keys", () => {
159            const expectedResult = "true;3;2;4;false;3;null;undefined;Z;X;Y;";
160
161            // First, ensure the test actually has the same behavior as a native Set.
162            let nativeSet = new Set<any>();
163            const nativeSetForEachResult = testSetIterationAddedValues(mixedKeys, nativeSet, /* useForEach */ true);
164            assert.equal(nativeSetForEachResult, expectedResult, "nativeSet-forEach");
165
166            nativeSet = new Set<any>();
167            const nativeSetIteratorResult = testSetIterationAddedValues(mixedKeys, nativeSet, /* useForEach */ false);
168            assert.equal(nativeSetIteratorResult, expectedResult, "nativeSet-iterator");
169
170            // Then, test the set shim.
171            let localshimSet = new SetShim<any>();
172            const shimSetForEachResult = testSetIterationAddedValues(mixedKeys, localshimSet, /* useForEach */ true);
173            assert.equal(shimSetForEachResult, expectedResult, "shimSet-forEach");
174
175            localshimSet = new SetShim<any>();
176            const shimSetIteratorResult = testSetIterationAddedValues(mixedKeys, localshimSet, /* useForEach */ false);
177            assert.equal(shimSetIteratorResult, expectedResult, "shimSet-iterator");
178        });
179
180        it("create from Array", () => {
181            const set = new SetShim(["a"]);
182            assert.equal(set.size, 1);
183            assert.isTrue(set.has("a"));
184        });
185
186        it("create from set", () => {
187            const set1 = new SetShim(["a"]);
188            const set2 = new SetShim(set1);
189            assert.equal(set1.size, 1);
190            assert.equal(set2.size, 1);
191            assert.isTrue(set2.has("a"));
192        });
193
194        it("add when not present", () => {
195            const set = new SetShim<string>();
196            const result = set.add("a");
197            assert.equal(set.size, 1);
198            assert.strictEqual(result, set);
199            assert.isTrue(set.has("a"));
200        });
201
202        it("add when present", () => {
203            const set = new SetShim<string>();
204            set.add("a");
205            const result = set.add("a");
206            assert.equal(set.size, 1);
207            assert.strictEqual(result, set);
208            assert.isTrue(set.has("a"));
209        });
210
211        it("has when not present", () => {
212            const set = new SetShim<string>();
213            assert.isFalse(set.has("a"));
214        });
215
216        it("has when present", () => {
217            const set = new SetShim<string>();
218            set.add("a");
219            assert.isTrue(set.has("a"));
220        });
221
222        it("delete when not present", () => {
223            const set = new SetShim<string>();
224            assert.isFalse(set.delete("a"));
225        });
226
227        it("delete when present", () => {
228            const set = new SetShim<string>();
229            set.add("a");
230            assert.isTrue(set.delete("a"));
231        });
232
233        it("delete twice when present", () => {
234            const set = new SetShim<string>();
235            set.add("a");
236            assert.isTrue(set.delete("a"));
237            assert.isFalse(set.delete("a"));
238        });
239
240        it("remove only item and iterate", () => {
241            const set = new SetShim<string>();
242            set.add("a");
243            set.delete("a");
244            const actual = arrayFrom(set.keys());
245            assert.deepEqual(actual, []);
246        });
247
248        it("remove first item and iterate", () => {
249            const set = new SetShim<string>();
250            set.add("a");
251            set.add("c");
252            set.delete("a");
253            assert.deepEqual(arrayFrom(set.keys()), ["c"]);
254            assert.deepEqual(arrayFrom(set.values()), ["c"]);
255            assert.deepEqual(arrayFrom(set.entries()), [["c", "c"]]);
256        });
257
258        it("remove last item and iterate", () => {
259            const set = new SetShim<string>();
260            set.add("a");
261            set.add("c");
262            set.delete("c");
263            assert.deepEqual(arrayFrom(set.keys()), ["a"]);
264            assert.deepEqual(arrayFrom(set.values()), ["a"]);
265            assert.deepEqual(arrayFrom(set.entries()), [["a", "a"]]);
266        });
267
268        it("remove middle item and iterate", () => {
269            const set = new SetShim<string>();
270            set.add("a");
271            set.add("c");
272            set.add("e");
273            set.delete("c");
274            assert.deepEqual(arrayFrom(set.keys()), ["a", "e"]);
275            assert.deepEqual(arrayFrom(set.values()), ["a", "e"]);
276            assert.deepEqual(arrayFrom(set.entries()), [["a", "a"], ["e", "e"]]);
277        });
278
279        it("keys", () => {
280            const set = new SetShim<string>();
281            set.add("c");
282            set.add("a");
283            assert.deepEqual(arrayFrom(set.keys()), ["c", "a"]);
284        });
285
286        it("values", () => {
287            const set = new SetShim<string>();
288            set.add("c");
289            set.add("a");
290            assert.deepEqual(arrayFrom(set.values()), ["c", "a"]);
291        });
292
293        it("entries", () => {
294            const set = new SetShim<string>();
295            set.add("c");
296            set.add("a");
297            assert.deepEqual(arrayFrom(set.entries()), [["c", "c"], ["a", "a"]]);
298        });
299
300        it("forEach", () => {
301            const set = new SetShim<string>();
302            set.add("c");
303            set.add("a");
304            const actual: [string, string][] = [];
305            set.forEach((value, key) => { actual.push([key, value]); });
306            assert.deepEqual(actual, [["c", "c"], ["a", "a"]]);
307        });
308    });
309}
310