View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host;
16  
17  import java.util.Map;
18  
19  import org.htmlunit.WebDriverTestCase;
20  import org.htmlunit.junit.annotation.Alerts;
21  import org.junit.jupiter.api.Test;
22  
23  /**
24   * Tests for {@link Map}.
25   *
26   * @author Ahmed Ashour
27   * @author Ronald Brill
28   */
29  public class MapTest extends WebDriverTestCase {
30  
31      /**
32       * @throws Exception if the test fails
33       */
34      @Test
35      @Alerts({"3", "value1"})
36      public void get() throws Exception {
37          final String html = DOCTYPE_HTML
38              + "<html><head>\n"
39              + "<script>\n"
40              + LOG_TITLE_FUNCTION
41              + "  function test() {\n"
42              + "    if (window.Map) {\n"
43              + "      var kvArray = [['key1', 'value1'], ['key2', 'value2']];\n"
44              + "      var myMap = new Map(kvArray);\n"
45              + "      myMap.set(1, 2);\n"
46              + "      log(myMap.size);\n"
47              + "      log(myMap.get('key1'));\n"
48              + "    }\n"
49              + "  }\n"
50              + "</script></head><body onload='test()'>\n"
51              + "</body></html>";
52  
53          loadPageVerifyTitle2(html);
54      }
55  
56      /**
57       * @throws Exception if the test fails
58       */
59      @Test
60      @Alerts({"function entries() { [native code] }",
61               "[object Map Iterator]", "0,foo", "1,bar", "[object Object],baz", "undefined"})
62      public void iterator() throws Exception {
63          final String html = DOCTYPE_HTML
64              + "<html>\n"
65              + "<head>\n"
66              + "<script>\n"
67              + LOG_TITLE_FUNCTION
68              + "  function test() {\n"
69              + "    if (window.Symbol) {\n"
70              + "      var myMap = new Map();\n"
71              + "      myMap.set('0', 'foo');\n"
72              + "      myMap.set(1, 'bar');\n"
73              + "      myMap.set({}, 'baz');\n"
74              + "      log(myMap[Symbol.iterator]);\n"
75              + "      var iter = myMap[Symbol.iterator]();\n"
76              + "      log(iter);\n"
77              + "      log(iter.next().value);\n"
78              + "      log(iter.next().value);\n"
79              + "      log(iter.next().value);\n"
80              + "      log(iter.next().value);\n"
81              + "    }\n"
82              + "  }\n"
83              + "</script>\n"
84              + "</head>\n"
85              + "<body onload='test()'>\n"
86              + "</body></html>";
87  
88          loadPageVerifyTitle2(html);
89      }
90  
91      /**
92       * @throws Exception if the test fails
93       */
94      @Test
95      @Alerts({"function entries() { [native code] }",
96               "[object Map Iterator]", "0,foo", "1,bar", "[object Object],baz", "undefined"})
97      public void entries() throws Exception {
98          final String html = DOCTYPE_HTML
99              + "<html>\n"
100             + "<head>\n"
101             + "<script>\n"
102             + LOG_TITLE_FUNCTION
103             + "  function test() {\n"
104             + "    if (window.Symbol) {\n"
105             + "      var myMap = new Map();\n"
106             + "      myMap.set('0', 'foo');\n"
107             + "      myMap.set(1, 'bar');\n"
108             + "      myMap.set({}, 'baz');\n"
109             + "      log(myMap.entries);\n"
110             + "      var iter = myMap.entries();\n"
111             + "      log(iter);\n"
112             + "      log(iter.next().value);\n"
113             + "      log(iter.next().value);\n"
114             + "      log(iter.next().value);\n"
115             + "      log(iter.next().value);\n"
116             + "    }\n"
117             + "  }\n"
118             + "</script>\n"
119             + "</head>\n"
120             + "<body onload='test()'>\n"
121             + "</body></html>";
122 
123         loadPageVerifyTitle2(html);
124     }
125 
126     /**
127      * @throws Exception if the test fails
128      */
129     @Test
130     @Alerts({"function values() { [native code] }",
131              "[object Map Iterator]", "foo", "bar", "baz", "undefined"})
132     public void values() throws Exception {
133         final String html = DOCTYPE_HTML
134             + "<html>\n"
135             + "<head>\n"
136             + "<script>\n"
137             + LOG_TITLE_FUNCTION
138             + "  function test() {\n"
139             + "    if (window.Symbol) {\n"
140             + "      var myMap = new Map();\n"
141             + "      myMap.set('0', 'foo');\n"
142             + "      myMap.set(1, 'bar');\n"
143             + "      myMap.set({}, 'baz');\n"
144             + "      log(myMap.values);\n"
145             + "      var iter = myMap.values();\n"
146             + "      log(iter);\n"
147             + "      log(iter.next().value);\n"
148             + "      log(iter.next().value);\n"
149             + "      log(iter.next().value);\n"
150             + "      log(iter.next().value);\n"
151             + "    }\n"
152             + "  }\n"
153             + "</script>\n"
154             + "</head>\n"
155             + "<body onload='test()'>\n"
156             + "</body></html>";
157 
158         loadPageVerifyTitle2(html);
159     }
160 
161     /**
162      * @throws Exception if the test fails
163      */
164     @Test
165     @Alerts({"function keys() { [native code] }",
166              "[object Map Iterator]", "0", "1", "[object Object]", "undefined"})
167     public void keys() throws Exception {
168         final String html = DOCTYPE_HTML
169             + "<html>\n"
170             + "<head>\n"
171             + "<script>\n"
172             + LOG_TITLE_FUNCTION
173             + "  function test() {\n"
174             + "    if (window.Symbol) {\n"
175             + "      var myMap = new Map();\n"
176             + "      myMap.set('0', 'foo');\n"
177             + "      myMap.set(1, 'bar');\n"
178             + "      myMap.set({}, 'baz');\n"
179             + "      log(myMap.keys);\n"
180             + "      var iter = myMap.keys();\n"
181             + "      log(iter);\n"
182             + "      log(iter.next().value);\n"
183             + "      log(iter.next().value);\n"
184             + "      log(iter.next().value);\n"
185             + "      log(iter.next().value);\n"
186             + "    }\n"
187             + "  }\n"
188             + "</script>\n"
189             + "</head>\n"
190             + "<body onload='test()'>\n"
191             + "</body></html>";
192 
193         loadPageVerifyTitle2(html);
194     }
195 
196     /**
197      * @throws Exception if the test fails
198      */
199     @Test
200     @Alerts("2")
201     public void constructorArray() throws Exception {
202         final String html = DOCTYPE_HTML
203             + "<html><head>\n"
204             + "<script>\n"
205             + LOG_TITLE_FUNCTION
206             + "function test() {\n"
207             + "  var myMap = new Map([[ 1, 'one' ],[ 2, 'two' ]]);\n"
208             + "  log(myMap.size);\n"
209             + "}\n"
210             + "</script></head><body onload='test()'>\n"
211             + "</body></html>";
212 
213         loadPageVerifyTitle2(html);
214     }
215 
216     /**
217      * @throws Exception if the test fails
218      */
219     @Test
220     @Alerts("TypeError")
221     public void constructorInt32Array() throws Exception {
222         final String html = DOCTYPE_HTML
223             + "<html><head>\n"
224             + "<script>\n"
225             + LOG_TITLE_FUNCTION
226             + "function test() {\n"
227             + "  var array = new Int32Array([2, 7]);\n"
228             + "  try {\n"
229             + "    var myMap = new Map(array);\n"
230             + "    log(myMap.size);\n"
231             + "  } catch(e) {\n"
232             + "    logEx(e);\n"
233             + "  }\n"
234             + "}\n"
235             + "</script></head><body onload='test()'>\n"
236             + "</body></html>";
237 
238         loadPageVerifyTitle2(html);
239     }
240 
241     /**
242      * @throws Exception if the test fails
243      */
244     @Test
245     @Alerts("TypeError")
246     public void constructorStringParam() throws Exception {
247         final String html = DOCTYPE_HTML
248             + "<html><head>\n"
249             + "<script>\n"
250             + LOG_TITLE_FUNCTION
251             + "function test() {\n"
252             + "  try {\n"
253             + "    var myMap = new Map('test');\n"
254             + "    log(myMap.size);\n"
255             + "  } catch(e) {\n"
256             + "    logEx(e);\n"
257             + "  }\n"
258             + "}\n"
259             + "</script></head><body onload='test()'>\n"
260             + "</body></html>";
261 
262         loadPageVerifyTitle2(html);
263     }
264 
265     /**
266      * @throws Exception if the test fails
267      */
268     @Test
269     @Alerts("TypeError")
270     public void constructorSetParam() throws Exception {
271         final String html = DOCTYPE_HTML
272             + "<html><head>\n"
273             + "<script>\n"
274             + LOG_TITLE_FUNCTION
275             + "function test() {\n"
276             + "  try {\n"
277             + "    var myMap = new Map(new Set('test'));\n"
278             + "    log(myMap.size);\n"
279             + "  } catch(e) {\n"
280             + "    logEx(e);\n"
281             + "  }\n"
282             + "}\n"
283             + "</script></head><body onload='test()'>\n"
284             + "</body></html>";
285 
286         loadPageVerifyTitle2(html);
287     }
288 
289     /**
290      * @throws Exception if the test fails
291      */
292     @Test
293     @Alerts("2")
294     public void constructorMapParam() throws Exception {
295         final String html = DOCTYPE_HTML
296             + "<html><head>\n"
297             + "<script>\n"
298             + LOG_TITLE_FUNCTION
299             + "function test() {\n"
300             + "  var kvArray = [['key1', 'value1'], ['key2', 'value2']];\n"
301             + "  var testMap = new Map(kvArray);\n"
302             + "  var myMap = new Map(testMap);\n"
303             + "  log(myMap.size);\n"
304             + "}\n"
305             + "</script></head><body onload='test()'>\n"
306             + "</body></html>";
307 
308         loadPageVerifyTitle2(html);
309     }
310 
311     /**
312      * @throws Exception if the test fails
313      */
314     @Test
315     @Alerts({"1", "77", "one"})
316     public void constructorIteratorParam() throws Exception {
317         final String html = DOCTYPE_HTML
318             + "<html><head>\n"
319             + "<script>\n"
320             + LOG_TITLE_FUNCTION
321             + "function logElement(value, key) {\n"
322             + "  log(key);\n"
323             + "  log(value);\n"
324             + "}\n"
325             + "function test() {\n"
326             + "  try {\n"
327             + "    var myIterable = {};\n"
328             + "    myIterable[Symbol.iterator] = function() {\n"
329             + "      return {\n"
330             + "        next: function() {\n"
331             + "          if (this._first) {;\n"
332             + "            this._first = false;\n"
333             + "            return { value: [ 77, 'one' ], done: false };\n"
334             + "          }\n"
335             + "          return { done: true };\n"
336             + "        },\n"
337             + "        _first: true\n"
338             + "      };\n"
339             + "    };\n"
340             + "    var myMap = new Map(myIterable);\n"
341             + "    log(myMap.size);\n"
342             + "    myMap.forEach(logElement);\n"
343             + "  }catch(e) { logEx(e); }"
344             + "}\n"
345             + "</script></head>\n"
346             + "<body onload='test()'>\n"
347             + "</body></html>";
348 
349         loadPageVerifyTitle2(html);
350     }
351 
352     /**
353      * @throws Exception if the test fails
354      */
355     @Test
356     @Alerts({"value1", "key1", "[object Map]", "[object Window]",
357              "[object Object]", "key2", "[object Map]", "[object Window]",
358              "null", "key3", "[object Map]", "[object Window]",
359              "undefined", "key4", "[object Map]", "[object Window]"})
360     public void forEach() throws Exception {
361         final String html = DOCTYPE_HTML
362             + "<html><head>\n"
363             + "<script>\n"
364             + LOG_TITLE_FUNCTION
365             + "function logElement(value, key, m) {\n"
366             + "  log(value);\n"
367             + "  log(key);\n"
368             + "  log(m);\n"
369             + "  log(this);\n"
370             + "}\n"
371             + "function test() {\n"
372             + "try {"
373             + "  var myMap = new Map([['key1', 'value1'], ['key2', {}], ['key3', null], ['key4', undefined]]);\n"
374             + "  myMap.forEach(logElement);\n"
375              + "}catch(e){log(e)}"
376             + "}\n"
377             + "</script>\n"
378             + "</head>\n"
379             + "<body onload='test()'>\n"
380             + "</body></html>";
381 
382         loadPageVerifyTitle2(html);
383     }
384 
385     /**
386      * @throws Exception if the test fails
387      */
388     @Test
389     @Alerts({"value1", "key1", "[object Map]", "undefined",
390              "[object Object]", "key2", "[object Map]", "undefined",
391              "null", "key3", "[object Map]", "undefined",
392              "undefined", "key4", "[object Map]", "undefined"})
393     public void forEachStrict() throws Exception {
394         final String html = DOCTYPE_HTML
395             + "<html><head>\n"
396             + "<script>\n"
397             + "'use strict';\n"
398             + LOG_TITLE_FUNCTION
399             + "function logElement(value, key, m) {\n"
400             + "  log(value);\n"
401             + "  log(key);\n"
402             + "  log(m);\n"
403             + "  log(this);\n"
404             + "}\n"
405             + "function test() {\n"
406             + "try {"
407             + "  var myMap = new Map([['key1', 'value1'], ['key2', {}], ['key3', null], ['key4', undefined]]);\n"
408             + "  myMap.forEach(logElement);\n"
409              + "}catch(e){log(e)}"
410             + "}\n"
411             + "</script>\n"
412             + "</head>\n"
413             + "<body onload='test()'>\n"
414             + "</body></html>";
415 
416         loadPageVerifyTitle2(html);
417     }
418 
419     /**
420      * @throws Exception if the test fails
421      */
422     @Test
423     @Alerts({"value1", "key1", "[object Map]", "hello",
424              "[object Object]", "key2", "[object Map]", "hello",
425              "null", "key3", "[object Map]", "hello",
426              "undefined", "key4", "[object Map]", "hello"})
427     public void forEachThis() throws Exception {
428         final String html = DOCTYPE_HTML
429             + "<html><head>\n"
430             + "<script>\n"
431             + LOG_TITLE_FUNCTION
432             + "function logElement(value, key, m) {\n"
433             + "  log(value);\n"
434             + "  log(key);\n"
435             + "  log(m);\n"
436             + "  log(this);\n"
437             + "}\n"
438             + "function test() {\n"
439             + "  var myMap = new Map([['key1', 'value1'], ['key2', {}], ['key3', null], ['key4', undefined]]);\n"
440             + "  myMap.forEach(logElement, 'hello');\n"
441             + "}\n"
442             + "</script></head><body onload='test()'>\n"
443             + "</body></html>";
444 
445         loadPageVerifyTitle2(html);
446     }
447 
448     /**
449      * Test case for Bug #1868.
450      *
451      * @throws Exception if the test fails
452      */
453     @Test
454     @Alerts("[object Map Iterator]")
455     public void iteratorPrototype() throws Exception {
456         final String html = DOCTYPE_HTML
457             + "<html>\n"
458             + "<head>\n"
459             + "<script>\n"
460             + LOG_TITLE_FUNCTION
461             + "  function test() {\n"
462             + "    if (window.Symbol) {\n"
463             + "      var myMap = new Map();\n"
464             + "      var iter = myMap[Symbol.iterator]();\n"
465             + "      log(Object.getPrototypeOf(iter));\n"
466             + "    }\n"
467             + "  }\n"
468             + "</script>\n"
469             + "</head>\n"
470             + "<body onload='test()'>\n"
471             + "</body></html>";
472 
473         loadPageVerifyTitle2(html);
474     }
475 
476     /**
477      * @throws Exception if the test fails
478      */
479     @Test
480     @Alerts({"value1", "undefined", "[object Map]", "[object Window]",
481              "[object Object]", "key2", "[object Map]", "[object Window]"})
482     public void forEach_withElision() throws Exception {
483         final String html = DOCTYPE_HTML
484             + "<html><head>\n"
485             + "<script>\n"
486             + LOG_TITLE_FUNCTION
487             + "function logElement(value, key, m) {\n"
488             + "  log(value);\n"
489             + "  log(key);\n"
490             + "  log(m);\n"
491             + "  log(this);\n"
492             + "}\n"
493             + "function test() {\n"
494             + "try {"
495             + "  var myMap = new Map([[, 'value1'], ['key2', {}]]);\n"
496             + "  myMap.forEach(logElement);\n"
497              + "}catch(e){log(e)}"
498             + "}\n"
499             + "</script></head><body onload='test()'>\n"
500             + "</body></html>";
501 
502         loadPageVerifyTitle2(html);
503     }
504 
505     /**
506      * @throws Exception if the test fails
507      */
508     @Test
509     @Alerts({"0", "0"})
510     public void setSize() throws Exception {
511         final String html = DOCTYPE_HTML
512             + "<html>\n"
513             + "<head>\n"
514             + "<script>\n"
515             + LOG_TITLE_FUNCTION
516             + "function test() {\n"
517             + "  var map = new Map();\n"
518             + "  try {\n"
519             + "    log(map.size);\n"
520             + "    map.size = 100;\n"
521             + "    log(map.size);\n"
522             + "  } catch(e) { log(e); }\n"
523             + "}\n"
524             + "</script></head>\n"
525             + "<body onload='test()'>\n"
526             + "</body></html>";
527 
528         loadPageVerifyTitle2(html);
529     }
530 
531     /**
532      * @throws Exception if the test fails
533      */
534     @Test
535     @Alerts({"0", "Type error"})
536     public void setSizeStrictMode() throws Exception {
537         final String html = DOCTYPE_HTML
538             + "<html>\n"
539             + "<head>\n"
540             + "<script>\n"
541             + LOG_TITLE_FUNCTION
542             + "function test() {\n"
543             + "  'use strict';\n"
544             + "  var map = new Map();\n"
545             + "  try {\n"
546             + "    log(map.size);\n"
547             + "    map.size = 100;\n"
548             + "    log(map.size);\n"
549             + "  } catch(e) { log('Type error'); }\n"
550             + "}\n"
551             + "</script></head>\n"
552             + "<body onload='test()'>\n"
553             + "</body></html>";
554 
555         loadPageVerifyTitle2(html);
556     }
557 
558 }