Revamp how idlharness.js handles iterable declarations (#14629)

Instead of adding IDL interface members in `add_iterable_members` in
the style of what webidl2.js would have added if the declaration were
expanded, instead test directly for what effect a single `iterable<T>`
or `iterable<T1,T2>` declaration should have.

This is more along the lines of `test_member_stringifier`, where no
`toString` is added as IDL members.

Alternative to https://github.com/web-platform-tests/wpt/pull/9790.
diff --git a/interfaces/dom.idl b/interfaces/dom.idl
index 503c391..3222b5d 100644
--- a/interfaces/dom.idl
+++ b/interfaces/dom.idl
@@ -145,7 +145,7 @@
 interface NodeList {
   getter Node? item(unsigned long index);
   readonly attribute unsigned long length;
-//  iterable<Node>;
+  iterable<Node>;
 };
 
 [Exposed=Window, LegacyUnenumerableNamedProperties]
@@ -548,5 +548,5 @@
   [CEReactions] boolean replace(DOMString token, DOMString newToken);
   boolean supports(DOMString token);
   [CEReactions] stringifier attribute DOMString value;
-  //  iterable<DOMString>;
+  iterable<DOMString>;
 };
diff --git a/resources/idlharness.js b/resources/idlharness.js
index 926a615..8b7a1e2 100644
--- a/resources/idlharness.js
+++ b/resources/idlharness.js
@@ -2309,21 +2309,6 @@
     }
 }
 
-IdlInterface.prototype.add_iterable_members = function(member)
-{
-    this.members.push(new IdlInterfaceMember(
-        { type: "operation", name: "entries", idlType: "iterator", arguments: []}));
-    this.members.push(new IdlInterfaceMember(
-        { type: "operation", name: "keys", idlType: "iterator", arguments: []}));
-    this.members.push(new IdlInterfaceMember(
-        { type: "operation", name: "values", idlType: "iterator", arguments: []}));
-    this.members.push(new IdlInterfaceMember(
-        { type: "operation", name: "forEach", idlType: "void",
-          arguments:
-          [{ name: "callback", idlType: {idlType: "function"}},
-           { name: "thisValue", idlType: {idlType: "any"}, optional: true}]}));
-};
-
 IdlInterface.prototype.test_to_json_operation = function(memberHolderObject, member) {
     var instanceName = memberHolderObject && memberHolderObject.constructor.name
         || member.name + " object";
@@ -2351,27 +2336,29 @@
 
 IdlInterface.prototype.test_member_iterable = function(member)
 {
-    var isPairIterator = member.idlType.length === 2;
     subsetTestByKey(this.name, test, function()
     {
-        var descriptor = Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, Symbol.iterator);
-        assert_true(descriptor.writable, "property should be writable");
-        assert_true(descriptor.configurable, "property should be configurable");
-        assert_false(descriptor.enumerable, "property should not be enumerable");
-        assert_equals(this.get_interface_object().prototype[Symbol.iterator].name, isPairIterator ? "entries" : "values", "@@iterator function does not have the right name");
-    }.bind(this), "Testing Symbol.iterator property of iterable interface " + this.name);
+        var isPairIterator = member.idlType.length === 2;
+        var proto = this.get_interface_object().prototype;
+        var descriptor = Object.getOwnPropertyDescriptor(proto, Symbol.iterator);
 
-    if (isPairIterator) {
-        subsetTestByKey(this.name, test, function() {
-            assert_equals(this.get_interface_object().prototype[Symbol.iterator], this.get_interface_object().prototype["entries"], "entries method is not the same as @@iterator");
-        }.bind(this), "Testing pair iterable interface " + this.name);
-    } else {
-        subsetTestByKey(this.name, test, function() {
-            ["entries", "keys", "values", "forEach", Symbol.Iterator].forEach(function(property) {
-                assert_equals(this.get_interface_object().prototype[property], Array.prototype[property], property + " function is not the same as Array one");
+        assert_true(descriptor.writable, "@@iterator property should be writable");
+        assert_true(descriptor.configurable, "@@iterator property should be configurable");
+        assert_false(descriptor.enumerable, "@@iterator property should not be enumerable");
+        assert_equals(typeof descriptor.value, "function", "@@iterator property should be a function");
+        assert_equals(descriptor.value.length, 0, "@@iterator function object length should be 0");
+        assert_equals(descriptor.value.name, isPairIterator ? "entries" : "values", "@@iterator function object should have the right name");
+
+        if (isPairIterator) {
+            assert_equals(proto["entries"], proto[Symbol.iterator], "entries method should be the same as @@iterator method");
+        } else {
+            assert_equals(proto[Symbol.iterator], Array.prototype[Symbol.iterator], "@@iterator method should be the same as Array prototype's");
+            ["entries", "keys", "values", "forEach", Symbol.iterator].forEach(function(property) {
+                var propertyName = property === Symbol.iterator ? "@@iterator" : property;
+                assert_equals(proto[property], Array.prototype[property], propertyName + " method should be the same as Array prototype's");
             }.bind(this));
-        }.bind(this), "Testing value iterable interface " + this.name);
-    }
+        }
+    }.bind(this), this.name + " interface: iterable<" + member.idlType.map(function(t) { return t.idlType; }).join(", ") + ">");
 };
 
 IdlInterface.prototype.test_member_stringifier = function(member)
@@ -2440,19 +2427,6 @@
     for (var i = 0; i < this.members.length; i++)
     {
         var member = this.members[i];
-        switch (member.type) {
-        case "iterable":
-            this.add_iterable_members(member);
-            break;
-        // TODO: add setlike and maplike handling.
-        default:
-            break;
-        }
-    }
-
-    for (var i = 0; i < this.members.length; i++)
-    {
-        var member = this.members[i];
         if (member.untested) {
             continue;
         }