From: <rb...@us...> - 2018-01-17 20:04:41
|
Revision: 15081 http://sourceforge.net/p/htmlunit/code/15081 Author: rbri Date: 2018-01-17 20:04:38 +0000 (Wed, 17 Jan 2018) Log Message: ----------- Set and Map constructor now supports user defined iterators also Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/ArrayCustom.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Iterator.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Map.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Set.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/MapTest.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/SetTest.java Modified: trunk/htmlunit/src/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2018-01-17 16:27:10 UTC (rev 15080) +++ trunk/htmlunit/src/changes/changes.xml 2018-01-17 20:04:38 UTC (rev 15081) @@ -8,7 +8,10 @@ <body> <release version="2.30" date="xx, 2018" description="Bugfixes, URLSearchParams implemented"> - <action type="change" dev="rbri"> + <action type="add" dev="rbri"> + JavaScript: Set and Map constructor now supports user defined iterators also. + </action> + <action type="add" dev="rbri"> JavaScript: Array.from() now supports user defined iterators also. </action> <action type="change" dev="rbri"> Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java 2018-01-17 16:27:10 UTC (rev 15080) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java 2018-01-17 20:04:38 UTC (rev 15081) @@ -1068,9 +1068,9 @@ @BrowserFeature(FF) JS_LOCATION_HREF_HASH_IS_ENCODED, - /** Map supports the argument constructor. */ - @BrowserFeature({CHROME, FF}) - JS_MAP_CONSTRUCTOR_ARGUMENT, + /** Map ignores the argument constructor. */ + @BrowserFeature(IE) + JS_MAP_CONSTRUCTOR_IGNORE_ARGUMENT, /** Indicates that an empty media list is represented by the string 'all'. */ @BrowserFeature(IE) @@ -1216,6 +1216,10 @@ @BrowserFeature(IE) JS_SELECT_SET_VALUES_CHECKS_ONLY_VALUE_ATTRIBUTE, + /** Set ignores the constructor argument. */ + @BrowserFeature(IE) + JS_SET_CONSTRUCTOR_IGNORE_ARGUMENT, + /** Whether to get any property from the items first. */ @BrowserFeature(IE) JS_STORAGE_GET_FROM_ITEMS, Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/ArrayCustom.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/ArrayCustom.java 2018-01-17 16:27:10 UTC (rev 15080) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/ArrayCustom.java 2018-01-17 20:04:38 UTC (rev 15081) @@ -17,15 +17,9 @@ import java.util.ArrayList; import java.util.List; -import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable; - -import net.sourceforge.htmlunit.corejs.javascript.BaseFunction; import net.sourceforge.htmlunit.corejs.javascript.Context; -import net.sourceforge.htmlunit.corejs.javascript.ES6Iterator; import net.sourceforge.htmlunit.corejs.javascript.Function; -import net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime; import net.sourceforge.htmlunit.corejs.javascript.Scriptable; -import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject; import net.sourceforge.htmlunit.corejs.javascript.Undefined; /** @@ -51,7 +45,7 @@ final Object arrayLike = args[0]; Object[] array = null; if (arrayLike instanceof Scriptable) { - Scriptable scriptable = (Scriptable) arrayLike; + final Scriptable scriptable = (Scriptable) arrayLike; final Object length = scriptable.get("length", scriptable); if (length != Scriptable.NOT_FOUND) { final int size = (int) Context.toNumber(length); @@ -60,55 +54,16 @@ array[i] = scriptable.get(i, scriptable); } } - - final Object iterator = scriptable.get(Symbol.ITERATOR_STRING, scriptable); - if (iterator != Scriptable.NOT_FOUND) { - final Object obj = ((BaseFunction) iterator) - .call(context, thisObj.getParentScope(), scriptable, new Object[0]); - - if (obj instanceof Iterator) { - final Iterator it = (Iterator) obj; - SimpleScriptable next = it.next(); - boolean done = (boolean) next.get(ES6Iterator.DONE_PROPERTY); - Object value = next.get(ES6Iterator.VALUE_PROPERTY); - - final List<Object> list = new ArrayList<>(); - while (!done) { + else { + final List<Object> list = new ArrayList<>(); + if (Iterator.iterate(context, thisObj, scriptable, + value -> { if (value != Undefined.instance) { list.add(value); } - next = it.next(); - done = (boolean) next.get(ES6Iterator.DONE_PROPERTY); - value = next.get(ES6Iterator.VALUE_PROPERTY); - } + })) { array = list.toArray(); } - else if (obj instanceof Scriptable) { - scriptable = (Scriptable) obj; - // handle user defined iterator - final Object nextFunct = scriptable.get(ES6Iterator.NEXT_METHOD, (Scriptable) obj); - if (!(nextFunct instanceof BaseFunction)) { - throw ScriptRuntime.typeError("undefined is not a function"); - } - final Object nextObj = ((BaseFunction) nextFunct) - .call(context, thisObj.getParentScope(), scriptable, new Object[0]); - - ScriptableObject next = (ScriptableObject) nextObj; - boolean done = (boolean) next.get(ES6Iterator.DONE_PROPERTY); - Object value = next.get(ES6Iterator.VALUE_PROPERTY); - - final List<Object> list = new ArrayList<>(); - while (!done) { - if (value != Undefined.instance) { - list.add(value); - } - next = (ScriptableObject) ((BaseFunction) nextFunct) - .call(context, thisObj.getParentScope(), scriptable, new Object[0]); - done = (boolean) next.get(ES6Iterator.DONE_PROPERTY); - value = next.get(ES6Iterator.VALUE_PROPERTY); - } - array = list.toArray(); - } } } else if (arrayLike instanceof String) { Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Iterator.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Iterator.java 2018-01-17 16:27:10 UTC (rev 15080) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Iterator.java 2018-01-17 20:04:38 UTC (rev 15081) @@ -14,11 +14,16 @@ */ package com.gargoylesoftware.htmlunit.javascript.host; +import java.util.function.Consumer; + import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable; +import net.sourceforge.htmlunit.corejs.javascript.BaseFunction; import net.sourceforge.htmlunit.corejs.javascript.Context; +import net.sourceforge.htmlunit.corejs.javascript.ES6Iterator; import net.sourceforge.htmlunit.corejs.javascript.FunctionObject; import net.sourceforge.htmlunit.corejs.javascript.NativeArray; +import net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime; import net.sourceforge.htmlunit.corejs.javascript.Scriptable; import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject; import net.sourceforge.htmlunit.corejs.javascript.Undefined; @@ -95,4 +100,65 @@ return object; } + /** + * Helper to support objects implementing the iterator interface. + * + * @param context the Context + * @param thisObj the this Object + * @param scriptable the scriptable + * @param processor the method to be called for every object + * @return true if @@iterator property was available + */ + public static boolean iterate(final Context context, + final Scriptable thisObj, + final Scriptable scriptable, + final Consumer<Object> processor) { + final Object iterator = scriptable.get(Symbol.ITERATOR_STRING, scriptable); + if (iterator == Scriptable.NOT_FOUND) { + return false; + } + + final Object obj = ((BaseFunction) iterator).call(context, thisObj.getParentScope(), scriptable, new Object[0]); + + if (obj instanceof Iterator) { + final Iterator it = (Iterator) obj; + SimpleScriptable next = it.next(); + boolean done = (boolean) next.get(ES6Iterator.DONE_PROPERTY); + Object value = next.get(ES6Iterator.VALUE_PROPERTY); + + while (!done) { + processor.accept(value); + + next = it.next(); + done = (boolean) next.get(ES6Iterator.DONE_PROPERTY); + value = next.get(ES6Iterator.VALUE_PROPERTY); + } + return true; + } + if (obj instanceof Scriptable) { + // handle user defined iterator + final Scriptable scriptableIterator = (Scriptable) obj; + final Object nextFunct = scriptableIterator.get(ES6Iterator.NEXT_METHOD, (Scriptable) obj); + if (!(nextFunct instanceof BaseFunction)) { + throw ScriptRuntime.typeError("undefined is not a function"); + } + final Object nextObj = ((BaseFunction) nextFunct) + .call(context, thisObj.getParentScope(), scriptableIterator, new Object[0]); + + ScriptableObject next = (ScriptableObject) nextObj; + boolean done = (boolean) next.get(ES6Iterator.DONE_PROPERTY); + Object value = next.get(ES6Iterator.VALUE_PROPERTY); + + while (!done) { + processor.accept(value); + + next = (ScriptableObject) ((BaseFunction) nextFunct) + .call(context, thisObj.getParentScope(), scriptableIterator, new Object[0]); + done = (boolean) next.get(ES6Iterator.DONE_PROPERTY); + value = next.get(ES6Iterator.VALUE_PROPERTY); + } + return true; + } + return false; + } } Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Map.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Map.java 2018-01-17 16:27:10 UTC (rev 15080) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Map.java 2018-01-17 20:04:38 UTC (rev 15081) @@ -14,7 +14,7 @@ */ package com.gargoylesoftware.htmlunit.javascript.host; -import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_MAP_CONSTRUCTOR_ARGUMENT; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_MAP_CONSTRUCTOR_IGNORE_ARGUMENT; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF; @@ -40,6 +40,7 @@ * A JavaScript object for {@code Map}. * * @author Ahmed Ashour + * @author Ronald Brill */ @JsxClass public class Map extends SimpleScriptable { @@ -56,41 +57,91 @@ /** * Creates an instance. - * @param iterable an Array or other iterable object + * @param arrayLike an Array or other iterable object */ @JsxConstructor - public Map(final Object iterable) { - if (iterable != Undefined.instance) { - final Window window = (Window) ScriptRuntime.getTopCallScope(Context.getCurrentContext()); - if (window.getBrowserVersion().hasFeature(JS_MAP_CONSTRUCTOR_ARGUMENT)) { - if (iterable instanceof NativeArray) { - final NativeArray array = (NativeArray) iterable; - for (int i = 0; i < array.getLength(); i++) { - final Object entryObject = array.get(i); - if (entryObject instanceof NativeArray) { - final Object[] entry = toArray((NativeArray) entryObject); + public Map(final Object arrayLike) { + if (arrayLike == Undefined.instance) { + return; + } + + final Context context = Context.getCurrentContext(); + final Window window = (Window) ScriptRuntime.getTopCallScope(context); + if (window.getBrowserVersion().hasFeature(JS_MAP_CONSTRUCTOR_IGNORE_ARGUMENT)) { + return; + } + + if (arrayLike instanceof NativeArray) { + final NativeArray array = (NativeArray) arrayLike; + for (int i = 0; i < array.getLength(); i++) { + final Object entryObject = array.get(i); + if (entryObject instanceof NativeArray) { + final Object[] entry = toArray((NativeArray) entryObject); + if (entry.length > 0) { + final Object key = entry[0]; + final Object value = entry.length > 1 ? entry[1] : null; + set(key, value); + } + } + else { + throw Context.reportRuntimeError("TypeError: object is not iterable (" + + entryObject.getClass().getName() + ")"); + } + } + return; + } + + if (arrayLike instanceof Map) { + final Map map = (Map) arrayLike; + map_.putAll(map.map_); + return; + } + + if (arrayLike instanceof Scriptable) { + final Scriptable scriptable = (Scriptable) arrayLike; + final Object length = scriptable.get("length", scriptable); + if (length != Scriptable.NOT_FOUND) { + final int size = (int) Context.toNumber(length); + for (int i = 0; i < size; i++) { + final Object entryObject = scriptable.get(i, scriptable); + if (entryObject instanceof NativeArray) { + final Object[] entry = toArray((NativeArray) entryObject); + if (entry.length > 0) { + final Object key = entry[0]; + final Object value = entry.length > 1 ? entry[1] : null; + set(key, value); + } + } + else { + throw Context.reportRuntimeError("TypeError: object is not iterable (" + + entryObject.getClass().getName() + ")"); + } + } + return; + } + + if (Iterator.iterate(context, this, scriptable, + value -> { + if (value != Undefined.instance) { + if (value instanceof NativeArray) { + final Object[] entry = toArray((NativeArray) value); if (entry.length > 0) { - final Object key = entry[0]; - final Object value = entry.length > 1 ? entry[1] : null; - set(key, value); + final Object entryKey = entry[0]; + final Object entryValue = entry.length > 1 ? entry[1] : null; + set(entryKey, entryValue); } } else { throw Context.reportRuntimeError("TypeError: object is not iterable (" - + entryObject.getClass().getName() + ")"); + + value.getClass().getName() + ")"); } } - } - else if (iterable instanceof Map) { - final Map map = (Map) iterable; - map_.putAll(map.map_); - } - else { - throw Context.reportRuntimeError("TypeError: object is not iterable (" - + iterable.getClass().getName() + ")"); - } + })) { + return; } } + + throw Context.reportRuntimeError("TypeError: object is not iterable (" + arrayLike.getClass().getName() + ")"); } /** @@ -245,19 +296,21 @@ */ @JsxFunction public void forEach(final Function callback, final Object thisArg) { - if (getBrowserVersion().hasFeature(JS_MAP_CONSTRUCTOR_ARGUMENT)) { - final Scriptable thisArgument; - if (thisArg instanceof Scriptable) { - thisArgument = (Scriptable) thisArg; - } - else { - thisArgument = getWindow(); - } - for (final java.util.Map.Entry<Object, Object> entry : map_.entrySet()) { - callback.call(Context.getCurrentContext(), getParentScope(), thisArgument, - new Object[] {entry.getValue(), entry.getKey(), this}); - } + if (getBrowserVersion().hasFeature(JS_MAP_CONSTRUCTOR_IGNORE_ARGUMENT)) { + return; } + + final Scriptable thisArgument; + if (thisArg instanceof Scriptable) { + thisArgument = (Scriptable) thisArg; + } + else { + thisArgument = getWindow(); + } + + for (final java.util.Map.Entry<Object, Object> entry : map_.entrySet()) { + callback.call(Context.getCurrentContext(), getParentScope(), thisArgument, + new Object[] {entry.getValue(), entry.getKey(), this}); + } } - } Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Set.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Set.java 2018-01-17 16:27:10 UTC (rev 15080) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Set.java 2018-01-17 20:04:38 UTC (rev 15081) @@ -14,7 +14,7 @@ */ package com.gargoylesoftware.htmlunit.javascript.host; -import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_MAP_CONSTRUCTOR_ARGUMENT; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_SET_CONSTRUCTOR_IGNORE_ARGUMENT; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF; @@ -41,6 +41,7 @@ * A JavaScript object for {@code Set}. * * @author Ahmed Ashour + * @author Ronald Brill */ @JsxClass public class Set extends SimpleScriptable { @@ -61,48 +62,70 @@ */ @JsxConstructor public Set(final Object iterable) { - if (iterable != Undefined.instance) { - final Window window = (Window) ScriptRuntime.getTopCallScope(Context.getCurrentContext()); - if (window.getBrowserVersion().hasFeature(JS_MAP_CONSTRUCTOR_ARGUMENT)) { - if (iterable instanceof NativeArray) { - final NativeArray array = (NativeArray) iterable; - for (int i = 0; i < array.getLength(); i++) { - add(ScriptableObject.getProperty(array, i)); - } - } - else if (iterable instanceof ArrayBufferViewBase) { - final ArrayBufferViewBase array = (ArrayBufferViewBase) iterable; - for (int i = 0; i < array.getLength(); i++) { - add(ScriptableObject.getProperty(array, i)); - } - } - else if (iterable instanceof String) { - final String string = (String) iterable; - for (int i = 0; i < string.length(); i++) { - add(String.valueOf(string.charAt(i))); - } - } - else if (iterable instanceof Set) { - final Set set = (Set) iterable; - for (Object object : set.set_) { - add(object); - } - } - else if (iterable instanceof Map) { - final Iterator iterator = (Iterator) ((Map) iterable).entries(); + if (iterable == Undefined.instance) { + return; + } + final Window window = (Window) ScriptRuntime.getTopCallScope(Context.getCurrentContext()); + if (window.getBrowserVersion().hasFeature(JS_SET_CONSTRUCTOR_IGNORE_ARGUMENT)) { + return; + } - SimpleScriptable object = iterator.next(); - while (Undefined.instance != object.get("value", null)) { - add(object); - object = iterator.next(); + if (iterable instanceof NativeArray) { + final NativeArray array = (NativeArray) iterable; + for (int i = 0; i < array.getLength(); i++) { + add(ScriptableObject.getProperty(array, i)); + } + return; + } + + if (iterable instanceof ArrayBufferViewBase) { + final ArrayBufferViewBase array = (ArrayBufferViewBase) iterable; + for (int i = 0; i < array.getLength(); i++) { + add(ScriptableObject.getProperty(array, i)); + } + return; + } + + if (iterable instanceof String) { + final String string = (String) iterable; + for (int i = 0; i < string.length(); i++) { + add(String.valueOf(string.charAt(i))); + } + return; + } + + if (iterable instanceof Set) { + final Set set = (Set) iterable; + for (Object object : set.set_) { + add(object); + } + return; + } + + if (iterable instanceof Map) { + final Iterator iterator = (Iterator) ((Map) iterable).entries(); + + SimpleScriptable object = iterator.next(); + while (Undefined.instance != object.get("value", null)) { + add(object); + object = iterator.next(); + } + return; + } + + if (iterable instanceof Scriptable) { + final Scriptable scriptable = (Scriptable) iterable; + if (Iterator.iterate(Context.getCurrentContext(), this, scriptable, + value -> { + if (value != Undefined.instance) { + add(value); } - } - else { - throw Context.reportRuntimeError("TypeError: object is not iterable (" - + iterable.getClass().getName() + ")"); - } + })) { + return; } } + + throw Context.reportRuntimeError("TypeError: object is not iterable (" + iterable.getClass().getName() + ")"); } /** @@ -198,19 +221,20 @@ */ @JsxFunction public void forEach(final Function callback, final Object thisArg) { - if (getBrowserVersion().hasFeature(JS_MAP_CONSTRUCTOR_ARGUMENT)) { - final Scriptable thisArgument; - if (thisArg instanceof Scriptable) { - thisArgument = (Scriptable) thisArg; - } - else { - thisArgument = getWindow(); - } - for (final Object object : set_) { - callback.call(Context.getCurrentContext(), getParentScope(), thisArgument, - new Object[] {object, object, this}); - } + if (getBrowserVersion().hasFeature(JS_SET_CONSTRUCTOR_IGNORE_ARGUMENT)) { + return; } + + final Scriptable thisArgument; + if (thisArg instanceof Scriptable) { + thisArgument = (Scriptable) thisArg; + } + else { + thisArgument = getWindow(); + } + for (final Object object : set_) { + callback.call(Context.getCurrentContext(), getParentScope(), thisArgument, + new Object[] {object, object, this}); + } } - } Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/MapTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/MapTest.java 2018-01-17 16:27:10 UTC (rev 15080) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/MapTest.java 2018-01-17 20:04:38 UTC (rev 15081) @@ -31,6 +31,7 @@ * Tests for {@link Map}. * * @author Ahmed Ashour + * @author Ronald Brill */ @RunWith(BrowserRunner.class) public class MapTest extends WebDriverTestCase { @@ -209,9 +210,28 @@ * @throws Exception if the test fails */ @Test + @Alerts(DEFAULT = "2", + IE = "0") + public void constructorArray() throws Exception { + final String html + = "<html><head><title>foo</title><script>\n" + + "function test() {\n" + + " var myMap = new Map([[ 1, 'one' ],[ 2, 'two' ]]);\n" + + " alert(myMap.size);\n" + + "}\n" + + "</script></head><body onload='test()'>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test @Alerts(DEFAULT = "exception", IE = "0") - public void constructor() throws Exception { + public void constructorInt32Array() throws Exception { final String html = "<html><head><title>foo</title><script>\n" + "function test() {\n" @@ -300,6 +320,46 @@ * @throws Exception if the test fails */ @Test + @Alerts(DEFAULT = {"1", "77", "one"}, + IE = "exception") + public void constructorIteratorParam() throws Exception { + final String html + = "<html><head><title>foo</title><script>\n" + + "function logElement(value, key) {\n" + + " alert(key);\n" + + " alert(value);\n" + + "}\n" + + "function test() {\n" + + " try {\n" + + " var myIterable = {};\n" + + " myIterable[Symbol.iterator] = function() {\n" + + " return {\n" + + " next: function() {\n" + + " if (this._first) {;\n" + + " this._first = false;\n" + + " return { value: [ 77, 'one' ], done: false };\n" + + " }\n" + + " return { done: true };\n" + + " },\n" + + " _first: true\n" + + " };\n" + + " };\n" + + " var myMap = new Map(myIterable);\n" + + " alert(myMap.size);\n" + + " myMap.forEach(logElement);\n" + + " }catch(e) { alert('exception'); }" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test @Alerts(DEFAULT = {"value1", "key1", "[object Map]", "[object Window]", "[object Object]", "key2", "[object Map]", "[object Window]", "null", "key3", "[object Map]", "[object Window]", Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/SetTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/SetTest.java 2018-01-17 16:27:10 UTC (rev 15080) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/SetTest.java 2018-01-17 20:04:38 UTC (rev 15081) @@ -31,6 +31,7 @@ * Tests for {@link Set}. * * @author Ahmed Ashour + * @author Ronald Brill */ @RunWith(BrowserRunner.class) public class SetTest extends WebDriverTestCase { @@ -139,10 +140,29 @@ @Test @Alerts(DEFAULT = "2", IE = "0") - public void constructor() throws Exception { + public void constructorArray() throws Exception { final String html = "<html><head><title>foo</title><script>\n" + "function test() {\n" + + " var mySet = new Set([2, 7]);\n" + + " alert(mySet.size);\n" + + "}\n" + + "</script></head><body onload='test()'>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = "2", + IE = "0") + public void constructorInt32Array() throws Exception { + final String html + = "<html><head><title>foo</title><script>\n" + + "function test() {\n" + " var array = new Int32Array([2, 7]);\n" + " var mySet = new Set(array);\n" + " alert(mySet.size);\n" @@ -222,6 +242,45 @@ * @throws Exception if the test fails */ @Test + @Alerts(DEFAULT = {"1", "#77"}, + IE = "exception") + public void constructorIteratorParam() throws Exception { + final String html + = "<html><head><title>foo</title><script>\n" + + "function logElement(value) {\n" + + " alert(value);\n" + + "}\n" + + "function test() {\n" + + " try {\n" + + " var myIterable = {};\n" + + " myIterable[Symbol.iterator] = function() {\n" + + " return {\n" + + " next: function() {\n" + + " if (this._first) {;\n" + + " this._first = false;\n" + + " return { value: '#77', done: false };\n" + + " }\n" + + " return { done: true };\n" + + " },\n" + + " _first: true\n" + + " };\n" + + " };\n" + + " var mySet = new Set(myIterable);\n" + + " alert(mySet.size);\n" + + " mySet.forEach(logElement);\n" + + " }catch(e) { alert('exception'); }" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test @Alerts(DEFAULT = {"ab", "ab", "[object Set]", "[object Window]", "undefined", "undefined", "[object Set]", "[object Window]", "null", "null", "[object Set]", "[object Window]"}, |