<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[203476] trunk/LayoutTests</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/203476">203476</a></dd>
<dt>Author</dt> <dd>jiewen_tan@apple.com</dd>
<dt>Date</dt> <dd>2016-07-20 16:14:39 -0700 (Wed, 20 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Fix timeout of imported/w3c/WebCryptoAPI/idlharness.html
https://bugs.webkit.org/show_bug.cgi?id=159979

Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

Add missing resources.

* WebCryptoAPI/idlharness-expected.txt:
* WebCryptoAPI/idlharness.html:
* resources/WebIDLParser.js: Added.
(tokenise):
(WebIDLParseError):
(WebIDLParseError.prototype.toString):
(error):
(consume):
(ws):
(all_ws):
(integer_type):
(float_type):
(primitive_type):
(const_value):
(type_suffix):
(single_type):
(union_type):
(type):
(argument):
(argument_list):
(type_pair):
(simple_extended_attr):
(extended_attrs):
(default_):
(const_):
(inheritance):
(operation_rest):
(callback):
(attribute):
(return_type):
(operation):
(identifiers):
(serialiser):
(iterable_type):
(readonly_iterable_type):
(iterable):
(interface_):
(partial):
(dictionary):
(exception):
(enum_):
(parse):
* resources/idlharness.js: Added.
(constValue):
(minOverloadLength):
(throwOrReject):
(awaitNCallbacks):
(return.fround):
(fround):
(self.IdlArray):
(IdlArray.prototype.add_idls):
(IdlArray.prototype.add_untested_idls):
(IdlArray.prototype.internal_add_idls):
(IdlArray.prototype.add_objects):
(IdlArray.prototype.prevent_multiple_testing):
(IdlArray.prototype.recursively_get_implements):
(exposed_in):
(IdlArray.prototype.test):
(IdlArray.prototype.assert_type_is):
(IdlObject):
(IdlObject.prototype.test):
(IdlObject.prototype.has_extended_attribute):
(IdlInterface):
(IdlInterface.prototype.is_callback):
(IdlInterface.prototype.has_constants):
(IdlInterface.prototype.is_global):
(IdlInterface.prototype.test):
(IdlInterface.prototype.test_self):
(IdlInterface.prototype.test_member_const):
(IdlInterface.prototype.test_member_attribute):
(IdlInterface.prototype.test_member_operation):
(IdlInterface.prototype.do_member_operation_asserts):
(IdlInterface.prototype.test_member_stringifier):
(IdlInterface.prototype.test_members):
(IdlInterface.prototype.test_object):
(IdlInterface.prototype.test_primary_interface_of):
(IdlInterface.prototype.test_interface_of):
(IdlInterface.prototype.has_stringifier):
(IdlInterface.prototype.do_interface_attribute_asserts):
(IdlInterfaceMember):
(create_suitable_object):
(IdlEnum):
(IdlTypedef):

LayoutTests:

* TestExpectations:
Remove the skip tuple of the test.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsimportedw3cChangeLog">trunk/LayoutTests/imported/w3c/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsimportedw3cWebCryptoAPIidlharnessexpectedtxt">trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt</a></li>
<li><a href="#trunkLayoutTestsimportedw3cWebCryptoAPIidlharnesshtml">trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness.html</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsimportedw3cresourcesWebIDLParserjs">trunk/LayoutTests/imported/w3c/resources/WebIDLParser.js</a></li>
<li><a href="#trunkLayoutTestsimportedw3cresourcesidlharnessjs">trunk/LayoutTests/imported/w3c/resources/idlharness.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (203475 => 203476)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-07-20 23:07:30 UTC (rev 203475)
+++ trunk/LayoutTests/ChangeLog        2016-07-20 23:14:39 UTC (rev 203476)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-07-20  Jiewen Tan  &lt;jiewen_tan@apple.com&gt;
+
+        Fix timeout of imported/w3c/WebCryptoAPI/idlharness.html
+        https://bugs.webkit.org/show_bug.cgi?id=159979
+
+        Reviewed by Alex Christensen.
+
+        * TestExpectations:
+        Remove the skip tuple of the test.
+
</ins><span class="cx"> 2016-07-20  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Stop using valueToStringWithNullCheck() in JSCSSStyleDeclaration::putDelegate()
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (203475 => 203476)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations        2016-07-20 23:07:30 UTC (rev 203475)
+++ trunk/LayoutTests/TestExpectations        2016-07-20 23:14:39 UTC (rev 203476)
</span><span class="lines">@@ -1038,7 +1038,6 @@
</span><span class="cx"> imported/w3c/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html [ Skip ]
</span><span class="cx"> imported/w3c/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html [ Skip ]
</span><span class="cx"> imported/w3c/WebCryptoAPI/generateKey/test_successes.html [ Skip ]
</span><del>-imported/w3c/WebCryptoAPI/idlharness.html [ Skip ]
</del><span class="cx"> 
</span><span class="cx"> editing/deleting/delete-emoji.html [ Slow ]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsimportedw3cChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/ChangeLog (203475 => 203476)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/ChangeLog        2016-07-20 23:07:30 UTC (rev 203475)
+++ trunk/LayoutTests/imported/w3c/ChangeLog        2016-07-20 23:14:39 UTC (rev 203476)
</span><span class="lines">@@ -1,3 +1,96 @@
</span><ins>+2016-07-20  Jiewen Tan  &lt;jiewen_tan@apple.com&gt;
+
+        Fix timeout of imported/w3c/WebCryptoAPI/idlharness.html
+        https://bugs.webkit.org/show_bug.cgi?id=159979
+
+        Reviewed by Alex Christensen.
+
+        Add missing resources.
+
+        * WebCryptoAPI/idlharness-expected.txt:
+        * WebCryptoAPI/idlharness.html:
+        * resources/WebIDLParser.js: Added.
+        (tokenise):
+        (WebIDLParseError):
+        (WebIDLParseError.prototype.toString):
+        (error):
+        (consume):
+        (ws):
+        (all_ws):
+        (integer_type):
+        (float_type):
+        (primitive_type):
+        (const_value):
+        (type_suffix):
+        (single_type):
+        (union_type):
+        (type):
+        (argument):
+        (argument_list):
+        (type_pair):
+        (simple_extended_attr):
+        (extended_attrs):
+        (default_):
+        (const_):
+        (inheritance):
+        (operation_rest):
+        (callback):
+        (attribute):
+        (return_type):
+        (operation):
+        (identifiers):
+        (serialiser):
+        (iterable_type):
+        (readonly_iterable_type):
+        (iterable):
+        (interface_):
+        (partial):
+        (dictionary):
+        (exception):
+        (enum_):
+        (parse):
+        * resources/idlharness.js: Added.
+        (constValue):
+        (minOverloadLength):
+        (throwOrReject):
+        (awaitNCallbacks):
+        (return.fround):
+        (fround):
+        (self.IdlArray):
+        (IdlArray.prototype.add_idls):
+        (IdlArray.prototype.add_untested_idls):
+        (IdlArray.prototype.internal_add_idls):
+        (IdlArray.prototype.add_objects):
+        (IdlArray.prototype.prevent_multiple_testing):
+        (IdlArray.prototype.recursively_get_implements):
+        (exposed_in):
+        (IdlArray.prototype.test):
+        (IdlArray.prototype.assert_type_is):
+        (IdlObject):
+        (IdlObject.prototype.test):
+        (IdlObject.prototype.has_extended_attribute):
+        (IdlInterface):
+        (IdlInterface.prototype.is_callback):
+        (IdlInterface.prototype.has_constants):
+        (IdlInterface.prototype.is_global):
+        (IdlInterface.prototype.test):
+        (IdlInterface.prototype.test_self):
+        (IdlInterface.prototype.test_member_const):
+        (IdlInterface.prototype.test_member_attribute):
+        (IdlInterface.prototype.test_member_operation):
+        (IdlInterface.prototype.do_member_operation_asserts):
+        (IdlInterface.prototype.test_member_stringifier):
+        (IdlInterface.prototype.test_members):
+        (IdlInterface.prototype.test_object):
+        (IdlInterface.prototype.test_primary_interface_of):
+        (IdlInterface.prototype.test_interface_of):
+        (IdlInterface.prototype.has_stringifier):
+        (IdlInterface.prototype.do_interface_attribute_asserts):
+        (IdlInterfaceMember):
+        (create_suitable_object):
+        (IdlEnum):
+        (IdlTypedef):
+
</ins><span class="cx"> 2016-07-20  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix null handling of HTMLFrameElement.marginWidth / marginHeight
</span></span></pre></div>
<a id="trunkLayoutTestsimportedw3cWebCryptoAPIidlharnessexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt (203475 => 203476)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt        2016-07-20 23:07:30 UTC (rev 203475)
+++ trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness-expected.txt        2016-07-20 23:14:39 UTC (rev 203476)
</span><span class="lines">@@ -1,2 +1,70 @@
</span><del>-FAIL: Timed out waiting for notifyDone to be called
</del><ins>+Description
</ins><span class="cx"> 
</span><ins>+This test verifies that the implementations of the WebCrypto API match with its WebIDL definition.
+
+
+PASS Crypto interface: existence and properties of interface object 
+PASS Crypto interface object length 
+PASS Crypto interface object name 
+PASS Crypto interface: existence and properties of interface prototype object 
+PASS Crypto interface: existence and properties of interface prototype object's &quot;constructor&quot; property 
+FAIL Crypto interface: attribute subtle assert_true: The prototype object must have a property &quot;subtle&quot; expected true got false
+PASS Crypto interface: operation getRandomValues(ArrayBufferView) 
+PASS Crypto must be primary interface of crypto 
+PASS Stringification of crypto 
+FAIL Crypto interface: crypto must inherit property &quot;subtle&quot; with the proper type (0) assert_inherits: property &quot;subtle&quot; not found in prototype chain
+PASS Crypto interface: crypto must inherit property &quot;getRandomValues&quot; with the proper type (1) 
+PASS Crypto interface: calling getRandomValues(ArrayBufferView) on crypto with too few arguments must throw TypeError 
+FAIL CryptoKey interface: existence and properties of interface object assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL CryptoKey interface object length assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL CryptoKey interface object name assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL CryptoKey interface: existence and properties of interface prototype object assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL CryptoKey interface: existence and properties of interface prototype object's &quot;constructor&quot; property assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL CryptoKey interface: attribute type assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL CryptoKey interface: attribute extractable assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL CryptoKey interface: attribute algorithm assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL CryptoKey interface: attribute usages assert_own_property: self does not have own property &quot;CryptoKey&quot; expected property &quot;CryptoKey&quot; missing
+FAIL SubtleCrypto interface: existence and properties of interface object assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface object length assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface object name assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: existence and properties of interface prototype object assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: existence and properties of interface prototype object's &quot;constructor&quot; property assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation encrypt(AlgorithmIdentifier,CryptoKey,BufferSource) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation decrypt(AlgorithmIdentifier,CryptoKey,BufferSource) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation sign(AlgorithmIdentifier,CryptoKey,BufferSource) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation verify(AlgorithmIdentifier,CryptoKey,BufferSource,BufferSource) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation digest(AlgorithmIdentifier,BufferSource) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation generateKey(AlgorithmIdentifier,boolean,[object Object]) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation deriveKey(AlgorithmIdentifier,CryptoKey,AlgorithmIdentifier,boolean,[object Object]) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation deriveBits(AlgorithmIdentifier,CryptoKey,unsigned long) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation importKey(KeyFormat,[object Object],[object Object],AlgorithmIdentifier,boolean,[object Object]) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation exportKey(KeyFormat,CryptoKey) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation wrapKey(KeyFormat,CryptoKey,CryptoKey,AlgorithmIdentifier) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto interface: operation unwrapKey(KeyFormat,BufferSource,CryptoKey,AlgorithmIdentifier,AlgorithmIdentifier,boolean,[object Object]) assert_own_property: self does not have own property &quot;SubtleCrypto&quot; expected property &quot;SubtleCrypto&quot; missing
+FAIL SubtleCrypto must be primary interface of crypto.subtle assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL Stringification of crypto.subtle assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;encrypt&quot; with the proper type (0) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling encrypt(AlgorithmIdentifier,CryptoKey,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;decrypt&quot; with the proper type (1) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling decrypt(AlgorithmIdentifier,CryptoKey,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;sign&quot; with the proper type (2) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling sign(AlgorithmIdentifier,CryptoKey,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;verify&quot; with the proper type (3) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling verify(AlgorithmIdentifier,CryptoKey,BufferSource,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;digest&quot; with the proper type (4) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling digest(AlgorithmIdentifier,BufferSource) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;generateKey&quot; with the proper type (5) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling generateKey(AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;deriveKey&quot; with the proper type (6) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling deriveKey(AlgorithmIdentifier,CryptoKey,AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;deriveBits&quot; with the proper type (7) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling deriveBits(AlgorithmIdentifier,CryptoKey,unsigned long) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;importKey&quot; with the proper type (8) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling importKey(KeyFormat,[object Object],[object Object],AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;exportKey&quot; with the proper type (9) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling exportKey(KeyFormat,CryptoKey) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;wrapKey&quot; with the proper type (10) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling wrapKey(KeyFormat,CryptoKey,CryptoKey,AlgorithmIdentifier) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: crypto.subtle must inherit property &quot;unwrapKey&quot; with the proper type (11) assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+FAIL SubtleCrypto interface: calling unwrapKey(KeyFormat,BufferSource,CryptoKey,AlgorithmIdentifier,AlgorithmIdentifier,boolean,[object Object]) on crypto.subtle with too few arguments must throw TypeError assert_equals: wrong typeof object expected &quot;object&quot; but got &quot;undefined&quot;
+
</ins></span></pre></div>
<a id="trunkLayoutTestsimportedw3cWebCryptoAPIidlharnesshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness.html (203475 => 203476)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness.html        2016-07-20 23:07:30 UTC (rev 203475)
+++ trunk/LayoutTests/imported/w3c/WebCryptoAPI/idlharness.html        2016-07-20 23:14:39 UTC (rev 203476)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+
</ins><span class="cx"> &lt;!doctype html&gt;
</span><span class="cx"> &lt;html&gt;
</span><span class="cx"> &lt;head&gt;
</span><span class="lines">@@ -7,8 +8,8 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;script src=../../../resources/testharness.js&gt;&lt;/script&gt;
</span><span class="cx"> &lt;script src=../../../resources/testharnessreport.js&gt;&lt;/script&gt;
</span><del>-&lt;script src=/resources/WebIDLParser.js&gt;&lt;/script&gt;
-&lt;script src=/resources/idlharness.js&gt;&lt;/script&gt;
</del><ins>+&lt;script src=../resources/WebIDLParser.js&gt;&lt;/script&gt;
+&lt;script src=../resources/idlharness.js&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/head&gt;
</span><span class="cx"> &lt;body&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsimportedw3cresourcesWebIDLParserjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/imported/w3c/resources/WebIDLParser.js (0 => 203476)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/resources/WebIDLParser.js                                (rev 0)
+++ trunk/LayoutTests/imported/w3c/resources/WebIDLParser.js        2016-07-20 23:14:39 UTC (rev 203476)
</span><span class="lines">@@ -0,0 +1,1012 @@
</span><ins>+
+
+(function () {
+    var tokenise = function (str) {
+        var tokens = []
+        ,   re = {
+                &quot;float&quot;:        /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/
+            ,   &quot;integer&quot;:      /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/
+            ,   &quot;identifier&quot;:   /^[A-Z_a-z][0-9A-Z_a-z]*/
+            ,   &quot;string&quot;:       /^&quot;[^&quot;]*&quot;/
+            ,   &quot;whitespace&quot;:   /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/
+            ,   &quot;other&quot;:        /^[^\t\n\r 0-9A-Z_a-z]/
+            }
+        ,   types = []
+        ;
+        for (var k in re) types.push(k);
+        while (str.length &gt; 0) {
+            var matched = false;
+            for (var i = 0, n = types.length; i &lt; n; i++) {
+                var type = types[i];
+                str = str.replace(re[type], function (tok) {
+                    tokens.push({ type: type, value: tok });
+                    matched = true;
+                    return &quot;&quot;;
+                });
+                if (matched) break;
+            }
+            if (matched) continue;
+            throw new Error(&quot;Token stream not progressing&quot;);
+        }
+        return tokens;
+    };
+    
+    var parse = function (tokens, opt) {
+        var line = 1;
+        tokens = tokens.slice();
+        
+        var FLOAT = &quot;float&quot;
+        ,   INT = &quot;integer&quot;
+        ,   ID = &quot;identifier&quot;
+        ,   STR = &quot;string&quot;
+        ,   OTHER = &quot;other&quot;
+        ;
+        
+        var WebIDLParseError = function (str, line, input, tokens) {
+            this.message = str;
+            this.line = line;
+            this.input = input;
+            this.tokens = tokens;
+        };
+        WebIDLParseError.prototype.toString = function () {
+            return this.message + &quot;, line &quot; + this.line + &quot; (tokens: '&quot; + this.input + &quot;')\n&quot; +
+                   JSON.stringify(this.tokens, null, 4);
+        };
+        
+        var error = function (str) {
+            var tok = &quot;&quot;, numTokens = 0, maxTokens = 5;
+            while (numTokens &lt; maxTokens &amp;&amp; tokens.length &gt; numTokens) {
+                tok += tokens[numTokens].value;
+                numTokens++;
+            }
+            throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5));
+        };
+        
+        var last_token = null;
+        
+        var consume = function (type, value) {
+            if (!tokens.length || tokens[0].type !== type) return;
+            if (typeof value === &quot;undefined&quot; || tokens[0].value === value) {
+                 last_token = tokens.shift();
+                 if (type === ID) last_token.value = last_token.value.replace(/^_/, &quot;&quot;);
+                 return last_token;
+             }
+        };
+        
+        var ws = function () {
+            if (!tokens.length) return;
+            if (tokens[0].type === &quot;whitespace&quot;) {
+                var t = tokens.shift();
+                t.value.replace(/\n/g, function (m) { line++; return m; });
+                return t;
+            }
+        };
+        
+        var all_ws = function (store, pea) { // pea == post extended attribute, tpea = same for types
+            var t = { type: &quot;whitespace&quot;, value: &quot;&quot; };
+            while (true) {
+                var w = ws();
+                if (!w) break;
+                t.value += w.value;
+            }
+            if (t.value.length &gt; 0) {
+                if (store) {
+                    var w = t.value
+                    ,   re = {
+                            &quot;ws&quot;:                   /^([\t\n\r ]+)/
+                        ,   &quot;line-comment&quot;:         /^\/\/(.*)\n?/m
+                        ,   &quot;multiline-comment&quot;:    /^\/\*((?:.|\n|\r)*?)\*\//
+                        }
+                    ,   wsTypes = []
+                    ;
+                    for (var k in re) wsTypes.push(k);
+                    while (w.length) {
+                        var matched = false;
+                        for (var i = 0, n = wsTypes.length; i &lt; n; i++) {
+                            var type = wsTypes[i];
+                            w = w.replace(re[type], function (tok, m1) {
+                                store.push({ type: type + (pea ? (&quot;-&quot; + pea) : &quot;&quot;), value: m1 });
+                                matched = true;
+                                return &quot;&quot;;
+                            });
+                            if (matched) break;
+                        }
+                        if (matched) continue;
+                        throw new Error(&quot;Surprising white space construct.&quot;); // this shouldn't happen
+                    }
+                }
+                return t;
+            }
+        };
+        
+        var integer_type = function () {
+            var ret = &quot;&quot;;
+            all_ws();
+            if (consume(ID, &quot;unsigned&quot;)) ret = &quot;unsigned &quot;;
+            all_ws();
+            if (consume(ID, &quot;short&quot;)) return ret + &quot;short&quot;;
+            if (consume(ID, &quot;long&quot;)) {
+                ret += &quot;long&quot;;
+                all_ws();
+                if (consume(ID, &quot;long&quot;)) return ret + &quot; long&quot;;
+                return ret;
+            }
+            if (ret) error(&quot;Failed to parse integer type&quot;);
+        };
+        
+        var float_type = function () {
+            var ret = &quot;&quot;;
+            all_ws();
+            if (consume(ID, &quot;unrestricted&quot;)) ret = &quot;unrestricted &quot;;
+            all_ws();
+            if (consume(ID, &quot;float&quot;)) return ret + &quot;float&quot;;
+            if (consume(ID, &quot;double&quot;)) return ret + &quot;double&quot;;
+            if (ret) error(&quot;Failed to parse float type&quot;);
+        };
+        
+        var primitive_type = function () {
+            var num_type = integer_type() || float_type();
+            if (num_type) return num_type;
+            all_ws();
+            if (consume(ID, &quot;boolean&quot;)) return &quot;boolean&quot;;
+            if (consume(ID, &quot;byte&quot;)) return &quot;byte&quot;;
+            if (consume(ID, &quot;octet&quot;)) return &quot;octet&quot;;
+        };
+        
+        var const_value = function () {
+            if (consume(ID, &quot;true&quot;)) return { type: &quot;boolean&quot;, value: true };
+            if (consume(ID, &quot;false&quot;)) return { type: &quot;boolean&quot;, value: false };
+            if (consume(ID, &quot;null&quot;)) return { type: &quot;null&quot; };
+            if (consume(ID, &quot;Infinity&quot;)) return { type: &quot;Infinity&quot;, negative: false };
+            if (consume(ID, &quot;NaN&quot;)) return { type: &quot;NaN&quot; };
+            var ret = consume(FLOAT) || consume(INT);
+            if (ret) return { type: &quot;number&quot;, value: 1 * ret.value };
+            var tok = consume(OTHER, &quot;-&quot;);
+            if (tok) {
+                if (consume(ID, &quot;Infinity&quot;)) return { type: &quot;Infinity&quot;, negative: true };
+                else tokens.unshift(tok);
+            }
+        };
+        
+        var type_suffix = function (obj) {
+            while (true) {
+                all_ws();
+                if (consume(OTHER, &quot;?&quot;)) {
+                    if (obj.nullable) error(&quot;Can't nullable more than once&quot;);
+                    obj.nullable = true;
+                }
+                else if (consume(OTHER, &quot;[&quot;)) {
+                    all_ws();
+                    consume(OTHER, &quot;]&quot;) || error(&quot;Unterminated array type&quot;);
+                    if (!obj.array) {
+                        obj.array = 1;
+                        obj.nullableArray = [obj.nullable];
+                    }
+                    else {
+                        obj.array++;
+                        obj.nullableArray.push(obj.nullable);
+                    }
+                    obj.nullable = false;
+                }
+                else return;
+            }
+        };
+        
+        var single_type = function () {
+            var prim = primitive_type()
+            ,   ret = { sequence: false, generic: null, nullable: false, array: false, union: false }
+            ,   name
+            ,   value
+            ;
+            if (prim) {
+                ret.idlType = prim;
+            }
+            else if (name = consume(ID)) {
+                value = name.value;
+                all_ws();
+                // Generic types
+                if (consume(OTHER, &quot;&lt;&quot;)) {
+                    // backwards compat
+                    if (value === &quot;sequence&quot;) {
+                        ret.sequence = true;
+                    }
+                    ret.generic = value;
+                    ret.idlType = type() || error(&quot;Error parsing generic type &quot; + value);
+                    all_ws();
+                    if (!consume(OTHER, &quot;&gt;&quot;)) error(&quot;Unterminated generic type &quot; + value);
+                    type_suffix(ret);
+                    return ret;
+                }
+                else {
+                    ret.idlType = value;
+                }
+            }
+            else {
+                return;
+            }
+            type_suffix(ret);
+            if (ret.nullable &amp;&amp; !ret.array &amp;&amp; ret.idlType === &quot;any&quot;) error(&quot;Type any cannot be made nullable&quot;);
+            return ret;
+        };
+        
+        var union_type = function () {
+            all_ws();
+            if (!consume(OTHER, &quot;(&quot;)) return;
+            var ret = { sequence: false, generic: null, nullable: false, array: false, union: true, idlType: [] };
+            var fst = type() || error(&quot;Union type with no content&quot;);
+            ret.idlType.push(fst);
+            while (true) {
+                all_ws();
+                if (!consume(ID, &quot;or&quot;)) break;
+                var typ = type() || error(&quot;No type after 'or' in union type&quot;);
+                ret.idlType.push(typ);
+            }
+            if (!consume(OTHER, &quot;)&quot;)) error(&quot;Unterminated union type&quot;);
+            type_suffix(ret);
+            return ret;
+        };
+        
+        var type = function () {
+            return single_type() || union_type();
+        };
+        
+        var argument = function (store) {
+            var ret = { optional: false, variadic: false };
+            ret.extAttrs = extended_attrs(store);
+            all_ws(store, &quot;pea&quot;);
+            var opt_token = consume(ID, &quot;optional&quot;);
+            if (opt_token) {
+                ret.optional = true;
+                all_ws();
+            }
+            ret.idlType = type();
+            if (!ret.idlType) {
+                if (opt_token) tokens.unshift(opt_token);
+                return;
+            }
+            var type_token = last_token;
+            if (!ret.optional) {
+                all_ws();
+                if (tokens.length &gt;= 3 &amp;&amp;
+                    tokens[0].type === &quot;other&quot; &amp;&amp; tokens[0].value === &quot;.&quot; &amp;&amp;
+                    tokens[1].type === &quot;other&quot; &amp;&amp; tokens[1].value === &quot;.&quot; &amp;&amp;
+                    tokens[2].type === &quot;other&quot; &amp;&amp; tokens[2].value === &quot;.&quot;
+                    ) {
+                    tokens.shift();
+                    tokens.shift();
+                    tokens.shift();
+                    ret.variadic = true;
+                }
+            }
+            all_ws();
+            var name = consume(ID);
+            if (!name) {
+                if (opt_token) tokens.unshift(opt_token);
+                tokens.unshift(type_token);
+                return;
+            }
+            ret.name = name.value;
+            if (ret.optional) {
+                all_ws();
+                ret[&quot;default&quot;] = default_();
+            }
+            return ret;
+        };
+        
+        var argument_list = function (store) {
+            var ret = []
+            ,   arg = argument(store ? ret : null)
+            ;
+            if (!arg) return;
+            ret.push(arg);
+            while (true) {
+                all_ws(store ? ret : null);
+                if (!consume(OTHER, &quot;,&quot;)) return ret;
+                var nxt = argument(store ? ret : null) || error(&quot;Trailing comma in arguments list&quot;);
+                ret.push(nxt);
+            }
+        };
+        
+        var type_pair = function () {
+            all_ws();
+            var k = type();
+            if (!k) return;
+            all_ws()
+            if (!consume(OTHER, &quot;,&quot;)) return;
+            all_ws();
+            var v = type();
+            if (!v) return;
+            return [k, v];
+        };
+        
+        var simple_extended_attr = function (store) {
+            all_ws();
+            var name = consume(ID);
+            if (!name) return;
+            var ret = {
+                name: name.value
+            ,   &quot;arguments&quot;: null
+            };
+            all_ws();
+            var eq = consume(OTHER, &quot;=&quot;);
+            if (eq) {
+                var rhs;
+                all_ws();
+                if (rhs = consume(ID)) {
+                  ret.rhs = rhs
+                }
+                else if (consume(OTHER, &quot;(&quot;)) {
+                    // [Exposed=(Window,Worker)]
+                    rhs = [];
+                    var id = consume(ID);
+                    if (id) {
+                      rhs = [id.value];
+                    }
+                    identifiers(rhs);
+                    consume(OTHER, &quot;)&quot;) || error(&quot;Unexpected token in extended attribute argument list or type pair&quot;);
+                    ret.rhs = {
+                        type: &quot;identifier-list&quot;,
+                        value: rhs
+                    };
+                }
+                if (!ret.rhs) return error(&quot;No right hand side to extended attribute assignment&quot;);
+            }
+            all_ws();
+            if (consume(OTHER, &quot;(&quot;)) {
+                var args, pair;
+                // [Constructor(DOMString str)]
+                if (args = argument_list(store)) {
+                    ret[&quot;arguments&quot;] = args;
+                }
+                // [MapClass(DOMString, DOMString)]
+                else if (pair = type_pair()) {
+                    ret.typePair = pair;
+                }
+                // [Constructor()]
+                else {
+                    ret[&quot;arguments&quot;] = [];
+                }
+                all_ws();
+                consume(OTHER, &quot;)&quot;) || error(&quot;Unexpected token in extended attribute argument list or type pair&quot;);
+            }
+            return ret;
+        };
+        
+        // Note: we parse something simpler than the official syntax. It's all that ever
+        // seems to be used
+        var extended_attrs = function (store) {
+            var eas = [];
+            all_ws(store);
+            if (!consume(OTHER, &quot;[&quot;)) return eas;
+            eas[0] = simple_extended_attr(store) || error(&quot;Extended attribute with not content&quot;);
+            all_ws();
+            while (consume(OTHER, &quot;,&quot;)) {
+                eas.push(simple_extended_attr(store) || error(&quot;Trailing comma in extended attribute&quot;));
+                all_ws();
+            }
+            consume(OTHER, &quot;]&quot;) || error(&quot;No end of extended attribute&quot;);
+            return eas;
+        };
+        
+        var default_ = function () {
+            all_ws();
+            if (consume(OTHER, &quot;=&quot;)) {
+                all_ws();
+                var def = const_value();
+                if (def) {
+                    return def;
+                }
+                else if (consume(OTHER, &quot;[&quot;)) {
+                    if (!consume(OTHER, &quot;]&quot;)) error(&quot;Default sequence value must be empty&quot;);
+                    return { type: &quot;sequence&quot;, value: [] };
+                }
+                else {
+                    var str = consume(STR) || error(&quot;No value for default&quot;);
+                    str.value = str.value.replace(/^&quot;/, &quot;&quot;).replace(/&quot;$/, &quot;&quot;);
+                    return str;
+                }
+            }
+        };
+        
+        var const_ = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            if (!consume(ID, &quot;const&quot;)) return;
+            var ret = { type: &quot;const&quot;, nullable: false };
+            all_ws();
+            var typ = primitive_type();
+            if (!typ) {
+                typ = consume(ID) || error(&quot;No type for const&quot;);
+                typ = typ.value;
+            }
+            ret.idlType = typ;
+            all_ws();
+            if (consume(OTHER, &quot;?&quot;)) {
+                ret.nullable = true;
+                all_ws();
+            }
+            var name = consume(ID) || error(&quot;No name for const&quot;);
+            ret.name = name.value;
+            all_ws();
+            consume(OTHER, &quot;=&quot;) || error(&quot;No value assignment for const&quot;);
+            all_ws();
+            var cnt = const_value();
+            if (cnt) ret.value = cnt;
+            else error(&quot;No value for const&quot;);
+            all_ws();
+            consume(OTHER, &quot;;&quot;) || error(&quot;Unterminated const&quot;);
+            return ret;
+        };
+        
+        var inheritance = function () {
+            all_ws();
+            if (consume(OTHER, &quot;:&quot;)) {
+                all_ws();
+                var inh = consume(ID) || error (&quot;No type in inheritance&quot;);
+                return inh.value;
+            }
+        };
+        
+        var operation_rest = function (ret, store) {
+            all_ws();
+            if (!ret) ret = {};
+            var name = consume(ID);
+            ret.name = name ? name.value : null;
+            all_ws();
+            consume(OTHER, &quot;(&quot;) || error(&quot;Invalid operation&quot;);
+            ret[&quot;arguments&quot;] = argument_list(store) || [];
+            all_ws();
+            consume(OTHER, &quot;)&quot;) || error(&quot;Unterminated operation&quot;);
+            all_ws();
+            consume(OTHER, &quot;;&quot;) || error(&quot;Unterminated operation&quot;);
+            return ret;
+        };
+        
+        var callback = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            var ret;
+            if (!consume(ID, &quot;callback&quot;)) return;
+            all_ws();
+            var tok = consume(ID, &quot;interface&quot;);
+            if (tok) {
+                tokens.unshift(tok);
+                ret = interface_();
+                ret.type = &quot;callback interface&quot;;
+                return ret;
+            }
+            var name = consume(ID) || error(&quot;No name for callback&quot;);
+            ret = { type: &quot;callback&quot;, name: name.value };
+            all_ws();
+            consume(OTHER, &quot;=&quot;) || error(&quot;No assignment in callback&quot;);
+            all_ws();
+            ret.idlType = return_type();
+            all_ws();
+            consume(OTHER, &quot;(&quot;) || error(&quot;No arguments in callback&quot;);
+            ret[&quot;arguments&quot;] = argument_list(store) || [];
+            all_ws();
+            consume(OTHER, &quot;)&quot;) || error(&quot;Unterminated callback&quot;);
+            all_ws();
+            consume(OTHER, &quot;;&quot;) || error(&quot;Unterminated callback&quot;);
+            return ret;
+        };
+
+        var attribute = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            var grabbed = []
+            ,   ret = {
+                type:           &quot;attribute&quot;
+            ,   &quot;static&quot;:       false
+            ,   stringifier:    false
+            ,   inherit:        false
+            ,   readonly:       false
+            };
+            if (consume(ID, &quot;static&quot;)) {
+                ret[&quot;static&quot;] = true;
+                grabbed.push(last_token);
+            }
+            else if (consume(ID, &quot;stringifier&quot;)) {
+                ret.stringifier = true;
+                grabbed.push(last_token);
+            }
+            var w = all_ws();
+            if (w) grabbed.push(w);
+            if (consume(ID, &quot;inherit&quot;)) {
+                if (ret[&quot;static&quot;] || ret.stringifier) error(&quot;Cannot have a static or stringifier inherit&quot;);
+                ret.inherit = true;
+                grabbed.push(last_token);
+                var w = all_ws();
+                if (w) grabbed.push(w);
+            }
+            if (consume(ID, &quot;readonly&quot;)) {
+                ret.readonly = true;
+                grabbed.push(last_token);
+                var w = all_ws();
+                if (w) grabbed.push(w);
+            }
+            if (!consume(ID, &quot;attribute&quot;)) {
+                tokens = grabbed.concat(tokens);
+                return;
+            }
+            all_ws();
+            ret.idlType = type() || error(&quot;No type in attribute&quot;);
+            if (ret.idlType.sequence) error(&quot;Attributes cannot accept sequence types&quot;);
+            all_ws();
+            var name = consume(ID) || error(&quot;No name in attribute&quot;);
+            ret.name = name.value;
+            all_ws();
+            consume(OTHER, &quot;;&quot;) || error(&quot;Unterminated attribute&quot;);
+            return ret;
+        };
+        
+        var return_type = function () {
+            var typ = type();
+            if (!typ) {
+                if (consume(ID, &quot;void&quot;)) {
+                    return &quot;void&quot;;
+                }
+                else error(&quot;No return type&quot;);
+            }
+            return typ;
+        };
+        
+        var operation = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            var ret = {
+                type:           &quot;operation&quot;
+            ,   getter:         false
+            ,   setter:         false
+            ,   creator:        false
+            ,   deleter:        false
+            ,   legacycaller:   false
+            ,   &quot;static&quot;:       false
+            ,   stringifier:    false
+            };
+            while (true) {
+                all_ws();
+                if (consume(ID, &quot;getter&quot;)) ret.getter = true;
+                else if (consume(ID, &quot;setter&quot;)) ret.setter = true;
+                else if (consume(ID, &quot;creator&quot;)) ret.creator = true;
+                else if (consume(ID, &quot;deleter&quot;)) ret.deleter = true;
+                else if (consume(ID, &quot;legacycaller&quot;)) ret.legacycaller = true;
+                else break;
+            }
+            if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
+                all_ws();
+                ret.idlType = return_type();
+                operation_rest(ret, store);
+                return ret;
+            }
+            if (consume(ID, &quot;static&quot;)) {
+                ret[&quot;static&quot;] = true;
+                ret.idlType = return_type();
+                operation_rest(ret, store);
+                return ret;
+            }
+            else if (consume(ID, &quot;stringifier&quot;)) {
+                ret.stringifier = true;-
+                all_ws();
+                if (consume(OTHER, &quot;;&quot;)) return ret;
+                ret.idlType = return_type();
+                operation_rest(ret, store);
+                return ret;
+            }
+            ret.idlType = return_type();
+            all_ws();
+            if (consume(ID, &quot;iterator&quot;)) {
+                all_ws();
+                ret.type = &quot;iterator&quot;;
+                if (consume(ID, &quot;object&quot;)) {
+                    ret.iteratorObject = &quot;object&quot;;
+                }
+                else if (consume(OTHER, &quot;=&quot;)) {
+                    all_ws();
+                    var name = consume(ID) || error(&quot;No right hand side in iterator&quot;);
+                    ret.iteratorObject = name.value;
+                }
+                all_ws();
+                consume(OTHER, &quot;;&quot;) || error(&quot;Unterminated iterator&quot;);
+                return ret;
+            }
+            else {
+                operation_rest(ret, store);
+                return ret;
+            }
+        };
+        
+        var identifiers = function (arr) {
+            while (true) {
+                all_ws();
+                if (consume(OTHER, &quot;,&quot;)) {
+                    all_ws();
+                    var name = consume(ID) || error(&quot;Trailing comma in identifiers list&quot;);
+                    arr.push(name.value);
+                }
+                else break;
+            }
+        };
+        
+        var serialiser = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            if (!consume(ID, &quot;serializer&quot;)) return;
+            var ret = { type: &quot;serializer&quot; };
+            all_ws();
+            if (consume(OTHER, &quot;=&quot;)) {
+                all_ws();
+                if (consume(OTHER, &quot;{&quot;)) {
+                    ret.patternMap = true;
+                    all_ws();
+                    var id = consume(ID);
+                    if (id &amp;&amp; id.value === &quot;getter&quot;) {
+                        ret.names = [&quot;getter&quot;];
+                    }
+                    else if (id &amp;&amp; id.value === &quot;inherit&quot;) {
+                        ret.names = [&quot;inherit&quot;];
+                        identifiers(ret.names);
+                    }
+                    else if (id) {
+                        ret.names = [id.value];
+                        identifiers(ret.names);
+                    }
+                    else {
+                        ret.names = [];
+                    }
+                    all_ws();
+                    consume(OTHER, &quot;}&quot;) || error(&quot;Unterminated serializer pattern map&quot;);
+                }
+                else if (consume(OTHER, &quot;[&quot;)) {
+                    ret.patternList = true;
+                    all_ws();
+                    var id = consume(ID);
+                    if (id &amp;&amp; id.value === &quot;getter&quot;) {
+                        ret.names = [&quot;getter&quot;];
+                    }
+                    else if (id) {
+                        ret.names = [id.value];
+                        identifiers(ret.names);
+                    }
+                    else {
+                        ret.names = [];
+                    }
+                    all_ws();
+                    consume(OTHER, &quot;]&quot;) || error(&quot;Unterminated serializer pattern list&quot;);
+                }
+                else {
+                    var name = consume(ID) || error(&quot;Invalid serializer&quot;);
+                    ret.name = name.value;
+                }
+                all_ws();
+                consume(OTHER, &quot;;&quot;) || error(&quot;Unterminated serializer&quot;);
+                return ret;
+            }
+            else if (consume(OTHER, &quot;;&quot;)) {
+                // noop, just parsing
+            }
+            else {
+                ret.idlType = return_type();
+                all_ws();
+                ret.operation = operation_rest(null, store);
+            }
+            return ret;
+        };
+
+        var iterable_type = function() {
+            if (consume(ID, &quot;iterable&quot;)) return &quot;iterable&quot;;
+            else if (consume(ID, &quot;legacyiterable&quot;)) return &quot;legacyiterable&quot;;
+            else if (consume(ID, &quot;maplike&quot;)) return &quot;maplike&quot;;
+            else if (consume(ID, &quot;setlike&quot;)) return &quot;setlike&quot;;
+            else return;
+        }
+
+        var readonly_iterable_type = function() {
+            if (consume(ID, &quot;maplike&quot;)) return &quot;maplike&quot;;
+            else if (consume(ID, &quot;setlike&quot;)) return &quot;setlike&quot;;
+            else return;
+        }
+
+        var iterable = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            var grabbed = [],
+                ret = {type: null, idlType: null, readonly: false};
+            if (consume(ID, &quot;readonly&quot;)) {
+                ret.readonly = true;
+                grabbed.push(last_token);
+                var w = all_ws();
+                if (w) grabbed.push(w);
+            }
+            var consumeItType = ret.readonly ? readonly_iterable_type : iterable_type;
+
+            var ittype = consumeItType();
+            if (!ittype) {
+                tokens = grabbed.concat(tokens);
+                return;
+            }
+
+            var secondTypeRequired = ittype === &quot;maplike&quot;;
+            var secondTypeAllowed = secondTypeRequired || ittype === &quot;iterable&quot;;
+            ret.type = ittype;
+            if (ret.type !== 'maplike' &amp;&amp; ret.type !== 'setlike')
+                delete ret.readonly;
+            all_ws();
+            if (consume(OTHER, &quot;&lt;&quot;)) {
+                ret.idlType = type() || error(&quot;Error parsing &quot; + ittype + &quot; declaration&quot;);
+                all_ws();
+                if (secondTypeAllowed) {
+                    var type2 = null;
+                    if (consume(OTHER, &quot;,&quot;)) {
+                        all_ws();
+                        type2 = type();
+                        all_ws();                        
+                    }
+                    if (type2)
+                        ret.idlType = [ret.idlType, type2];
+                    else if (secondTypeRequired)
+                        error(&quot;Missing second type argument in &quot; + ittype + &quot; declaration&quot;);
+                }
+                if (!consume(OTHER, &quot;&gt;&quot;)) error(&quot;Unterminated &quot; + ittype + &quot; declaration&quot;);
+                all_ws();
+                if (!consume(OTHER, &quot;;&quot;)) error(&quot;Missing semicolon after &quot; + ittype + &quot; declaration&quot;);
+            }
+            else
+                error(&quot;Error parsing &quot; + ittype + &quot; declaration&quot;);
+
+            return ret;            
+        }        
+        
+        var interface_ = function (isPartial, store) {
+            all_ws(isPartial ? null : store, &quot;pea&quot;);
+            if (!consume(ID, &quot;interface&quot;)) return;
+            all_ws();
+            var name = consume(ID) || error(&quot;No name for interface&quot;);
+            var mems = []
+            ,   ret = {
+                type:   &quot;interface&quot;
+            ,   name:   name.value
+            ,   partial:    false
+            ,   members:    mems
+            };
+            if (!isPartial) ret.inheritance = inheritance() || null;
+            all_ws();
+            consume(OTHER, &quot;{&quot;) || error(&quot;Bodyless interface&quot;);
+            while (true) {
+                all_ws(store ? mems : null);
+                if (consume(OTHER, &quot;}&quot;)) {
+                    all_ws();
+                    consume(OTHER, &quot;;&quot;) || error(&quot;Missing semicolon after interface&quot;);
+                    return ret;
+                }
+                var ea = extended_attrs(store ? mems : null);
+                all_ws();
+                var cnt = const_(store ? mems : null);
+                if (cnt) {
+                    cnt.extAttrs = ea;
+                    ret.members.push(cnt);
+                    continue;
+                }
+                var mem = (opt.allowNestedTypedefs &amp;&amp; typedef(store ? mems : null)) ||
+                          iterable(store ? mems : null) ||
+                          serialiser(store ? mems : null) ||
+                          attribute(store ? mems : null) ||
+                          operation(store ? mems : null) ||
+                          error(&quot;Unknown member&quot;);
+                mem.extAttrs = ea;
+                ret.members.push(mem);
+            }
+        };
+        
+        var partial = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            if (!consume(ID, &quot;partial&quot;)) return;
+            var thing = dictionary(true, store) ||
+                        interface_(true, store) ||
+                        error(&quot;Partial doesn't apply to anything&quot;);
+            thing.partial = true;
+            return thing;
+        };
+        
+        var dictionary = function (isPartial, store) {
+            all_ws(isPartial ? null : store, &quot;pea&quot;);
+            if (!consume(ID, &quot;dictionary&quot;)) return;
+            all_ws();
+            var name = consume(ID) || error(&quot;No name for dictionary&quot;);
+            var mems = []
+            ,   ret = {
+                type:   &quot;dictionary&quot;
+            ,   name:   name.value
+            ,   partial:    false
+            ,   members:    mems
+            };
+            if (!isPartial) ret.inheritance = inheritance() || null;
+            all_ws();
+            consume(OTHER, &quot;{&quot;) || error(&quot;Bodyless dictionary&quot;);
+            while (true) {
+                all_ws(store ? mems : null);
+                if (consume(OTHER, &quot;}&quot;)) {
+                    all_ws();
+                    consume(OTHER, &quot;;&quot;) || error(&quot;Missing semicolon after dictionary&quot;);
+                    return ret;
+                }
+                var ea = extended_attrs(store ? mems : null);
+                all_ws(store ? mems : null, &quot;pea&quot;);
+                var required = consume(ID, &quot;required&quot;);
+                var typ = type() || error(&quot;No type for dictionary member&quot;);
+                all_ws();
+                var name = consume(ID) || error(&quot;No name for dictionary member&quot;);
+                var dflt = default_();
+                if (required &amp;&amp; dflt) error(&quot;Required member must not have a default&quot;);
+                ret.members.push({
+                    type:       &quot;field&quot;
+                ,   name:       name.value
+                ,   required:   !!required
+                ,   idlType:    typ
+                ,   extAttrs:   ea
+                ,   &quot;default&quot;:  dflt
+                });
+                all_ws();
+                consume(OTHER, &quot;;&quot;) || error(&quot;Unterminated dictionary member&quot;);
+            }
+        };
+        
+        var exception = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            if (!consume(ID, &quot;exception&quot;)) return;
+            all_ws();
+            var name = consume(ID) || error(&quot;No name for exception&quot;);
+            var mems = []
+            ,   ret = {
+                type:   &quot;exception&quot;
+            ,   name:   name.value
+            ,   members:    mems
+            };
+            ret.inheritance = inheritance() || null;
+            all_ws();
+            consume(OTHER, &quot;{&quot;) || error(&quot;Bodyless exception&quot;);
+            while (true) {
+                all_ws(store ? mems : null);
+                if (consume(OTHER, &quot;}&quot;)) {
+                    all_ws();
+                    consume(OTHER, &quot;;&quot;) || error(&quot;Missing semicolon after exception&quot;);
+                    return ret;
+                }
+                var ea = extended_attrs(store ? mems : null);
+                all_ws(store ? mems : null, &quot;pea&quot;);
+                var cnt = const_();
+                if (cnt) {
+                    cnt.extAttrs = ea;
+                    ret.members.push(cnt);
+                }
+                else {
+                    var typ = type();
+                    all_ws();
+                    var name = consume(ID);
+                    all_ws();
+                    if (!typ || !name || !consume(OTHER, &quot;;&quot;)) error(&quot;Unknown member in exception body&quot;);
+                    ret.members.push({
+                        type:       &quot;field&quot;
+                    ,   name:       name.value
+                    ,   idlType:    typ
+                    ,   extAttrs:   ea
+                    });
+                }
+            }
+        };
+        
+        var enum_ = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            if (!consume(ID, &quot;enum&quot;)) return;
+            all_ws();
+            var name = consume(ID) || error(&quot;No name for enum&quot;);
+            var vals = []
+            ,   ret = {
+                type:   &quot;enum&quot;
+            ,   name:   name.value
+            ,   values: vals
+            };
+            all_ws();
+            consume(OTHER, &quot;{&quot;) || error(&quot;No curly for enum&quot;);
+            var saw_comma = false;
+            while (true) {
+                all_ws(store ? vals : null);
+                if (consume(OTHER, &quot;}&quot;)) {
+                    all_ws();
+                    consume(OTHER, &quot;;&quot;) || error(&quot;No semicolon after enum&quot;);
+                    return ret;
+                }
+                var val = consume(STR) || error(&quot;Unexpected value in enum&quot;);
+                ret.values.push(val.value.replace(/&quot;/g, &quot;&quot;));
+                all_ws(store ? vals : null);
+                if (consume(OTHER, &quot;,&quot;)) {
+                    if (store) vals.push({ type: &quot;,&quot; });
+                    all_ws(store ? vals : null);
+                    saw_comma = true;
+                }
+                else {
+                    saw_comma = false;
+                }
+            }
+        };
+        
+        var typedef = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            if (!consume(ID, &quot;typedef&quot;)) return;
+            var ret = {
+                type:   &quot;typedef&quot;
+            };
+            all_ws();
+            ret.typeExtAttrs = extended_attrs();
+            all_ws(store, &quot;tpea&quot;);
+            ret.idlType = type() || error(&quot;No type in typedef&quot;);
+            all_ws();
+            var name = consume(ID) || error(&quot;No name in typedef&quot;);
+            ret.name = name.value;
+            all_ws();
+            consume(OTHER, &quot;;&quot;) || error(&quot;Unterminated typedef&quot;);
+            return ret;
+        };
+        
+        var implements_ = function (store) {
+            all_ws(store, &quot;pea&quot;);
+            var target = consume(ID);
+            if (!target) return;
+            var w = all_ws();
+            if (consume(ID, &quot;implements&quot;)) {
+                var ret = {
+                    type:   &quot;implements&quot;
+                ,   target: target.value
+                };
+                all_ws();
+                var imp = consume(ID) || error(&quot;Incomplete implements statement&quot;);
+                ret[&quot;implements&quot;] = imp.value;
+                all_ws();
+                consume(OTHER, &quot;;&quot;) || error(&quot;No terminating ; for implements statement&quot;);
+                return ret;
+            }
+            else {
+                // rollback
+                tokens.unshift(w);
+                tokens.unshift(target);
+            }
+        };
+        
+        var definition = function (store) {
+            return  callback(store)             ||
+                    interface_(false, store)    ||
+                    partial(store)              ||
+                    dictionary(false, store)    ||
+                    exception(store)            ||
+                    enum_(store)                ||
+                    typedef(store)              ||
+                    implements_(store)
+                    ;
+        };
+        
+        var definitions = function (store) {
+            if (!tokens.length) return [];
+            var defs = [];
+            while (true) {
+                var ea = extended_attrs(store ? defs : null)
+                ,   def = definition(store ? defs : null);
+                if (!def) {
+                    if (ea.length) error(&quot;Stray extended attributes&quot;);
+                    break;
+                }
+                def.extAttrs = ea;
+                defs.push(def);
+            }
+            return defs;
+        };
+        var res = definitions(opt.ws);
+        if (tokens.length) error(&quot;Unrecognised tokens&quot;);
+        return res;
+    };
+
+    var inNode = typeof module !== &quot;undefined&quot; &amp;&amp; module.exports
+    ,   obj = {
+            parse:  function (str, opt) {
+                if (!opt) opt = {};
+                var tokens = tokenise(str);
+                return parse(tokens, opt);
+            }
+    };
+
+    if (inNode) module.exports = obj;
+    else        self.WebIDL2 = obj;
+}());
</ins></span></pre></div>
<a id="trunkLayoutTestsimportedw3cresourcesidlharnessjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/imported/w3c/resources/idlharness.js (0 => 203476)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/resources/idlharness.js                                (rev 0)
+++ trunk/LayoutTests/imported/w3c/resources/idlharness.js        2016-07-20 23:14:39 UTC (rev 203476)
</span><span class="lines">@@ -0,0 +1,1850 @@
</span><ins>+/*
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+*/
+
+/* For user documentation see docs/idlharness.md */
+
+/**
+ * Notes for people who want to edit this file (not just use it as a library):
+ *
+ * Most of the interesting stuff happens in the derived classes of IdlObject,
+ * especially IdlInterface.  The entry point for all IdlObjects is .test(),
+ * which is called by IdlArray.test().  An IdlObject is conceptually just
+ * &quot;thing we want to run tests on&quot;, and an IdlArray is an array of IdlObjects
+ * with some additional data thrown in.
+ *
+ * The object model is based on what WebIDLParser.js produces, which is in turn
+ * based on its pegjs grammar.  If you want to figure out what properties an
+ * object will have from WebIDLParser.js, the best way is to look at the
+ * grammar:
+ *
+ *   https://github.com/darobin/webidl.js/blob/master/lib/grammar.peg
+ *
+ * So for instance:
+ *
+ *   // interface definition
+ *   interface
+ *       =   extAttrs:extendedAttributeList? S? &quot;interface&quot; S name:identifier w herit:ifInheritance? w &quot;{&quot; w mem:ifMember* w &quot;}&quot; w &quot;;&quot; w
+ *           { return { type: &quot;interface&quot;, name: name, inheritance: herit, members: mem, extAttrs: extAttrs }; }
+ *
+ * This means that an &quot;interface&quot; object will have a .type property equal to
+ * the string &quot;interface&quot;, a .name property equal to the identifier that the
+ * parser found, an .inheritance property equal to either null or the result of
+ * the &quot;ifInheritance&quot; production found elsewhere in the grammar, and so on.
+ * After each grammatical production is a JavaScript function in curly braces
+ * that gets called with suitable arguments and returns some JavaScript value.
+ *
+ * (Note that the version of WebIDLParser.js we use might sometimes be
+ * out-of-date or forked.)
+ *
+ * The members and methods of the classes defined by this file are all at least
+ * briefly documented, hopefully.
+ */
+(function(){
+&quot;use strict&quot;;
+/// Helpers ///
+function constValue (cnt) {
+    if (cnt.type === &quot;null&quot;) return null;
+    if (cnt.type === &quot;NaN&quot;) return NaN;
+    if (cnt.type === &quot;Infinity&quot;) return cnt.negative ? -Infinity : Infinity;
+    return cnt.value;
+}
+
+function minOverloadLength(overloads) {
+    if (!overloads.length) {
+        return 0;
+    }
+
+    return overloads.map(function(attr) {
+        return attr.arguments ? attr.arguments.filter(function(arg) {
+            return !arg.optional &amp;&amp; !arg.variadic;
+        }).length : 0;
+    })
+    .reduce(function(m, n) { return Math.min(m, n); });
+}
+
+function throwOrReject(a_test, operation, fn, obj, args,  message, cb) {
+    if (operation.idlType.generic !== &quot;Promise&quot;) {
+        assert_throws(new TypeError(), function() {
+            fn.apply(obj, args);
+        }, message);
+        cb();
+    } else {
+        try {
+            promise_rejects(a_test, new TypeError(), fn.apply(obj, args)).then(cb, cb);
+        } catch (e){
+            a_test.step(function() {
+                assert_unreached(&quot;Throws \&quot;&quot; + e + &quot;\&quot; instead of rejecting promise&quot;);
+                cb();
+            });
+        }
+    }
+}
+
+function awaitNCallbacks(n, cb, ctx) {
+    var counter = 0;
+    return function() {
+        counter++;
+        if (counter &gt;= n) {
+            cb();
+        }
+    };
+}
+
+var fround = (function(){
+    if (Math.fround) return Math.fround;
+
+    var arr = new Float32Array(1);
+    return function fround(n) {
+        arr[0] = n;
+        return arr[0];
+    };
+})();
+
+/// IdlArray ///
+// Entry point
+self.IdlArray = function()
+//@{
+{
+    /**
+     * A map from strings to the corresponding named IdlObject, such as
+     * IdlInterface or IdlException.  These are the things that test() will run
+     * tests on.
+     */
+    this.members = {};
+
+    /**
+     * A map from strings to arrays of strings.  The keys are interface or
+     * exception names, and are expected to also exist as keys in this.members
+     * (otherwise they'll be ignored).  This is populated by add_objects() --
+     * see documentation at the start of the file.  The actual tests will be
+     * run by calling this.members[name].test_object(obj) for each obj in
+     * this.objects[name].  obj is a string that will be eval'd to produce a
+     * JavaScript value, which is supposed to be an object implementing the
+     * given IdlObject (interface, exception, etc.).
+     */
+    this.objects = {};
+
+    /**
+     * When adding multiple collections of IDLs one at a time, an earlier one
+     * might contain a partial interface or implements statement that depends
+     * on a later one.  Save these up and handle them right before we run
+     * tests.
+     *
+     * .partials is simply an array of objects from WebIDLParser.js'
+     * &quot;partialinterface&quot; production.  .implements maps strings to arrays of
+     * strings, such that
+     *
+     *   A implements B;
+     *   A implements C;
+     *   D implements E;
+     *
+     * results in { A: [&quot;B&quot;, &quot;C&quot;], D: [&quot;E&quot;] }.
+     */
+    this.partials = [];
+    this[&quot;implements&quot;] = {};
+};
+
+//@}
+IdlArray.prototype.add_idls = function(raw_idls)
+//@{
+{
+    /** Entry point.  See documentation at beginning of file. */
+    this.internal_add_idls(WebIDL2.parse(raw_idls));
+};
+
+//@}
+IdlArray.prototype.add_untested_idls = function(raw_idls)
+//@{
+{
+    /** Entry point.  See documentation at beginning of file. */
+    var parsed_idls = WebIDL2.parse(raw_idls);
+    for (var i = 0; i &lt; parsed_idls.length; i++)
+    {
+        parsed_idls[i].untested = true;
+        if (&quot;members&quot; in parsed_idls[i])
+        {
+            for (var j = 0; j &lt; parsed_idls[i].members.length; j++)
+            {
+                parsed_idls[i].members[j].untested = true;
+            }
+        }
+    }
+    this.internal_add_idls(parsed_idls);
+};
+
+//@}
+IdlArray.prototype.internal_add_idls = function(parsed_idls)
+//@{
+{
+    /**
+     * Internal helper called by add_idls() and add_untested_idls().
+     * parsed_idls is an array of objects that come from WebIDLParser.js's
+     * &quot;definitions&quot; production.  The add_untested_idls() entry point
+     * additionally sets an .untested property on each object (and its
+     * .members) so that they'll be skipped by test() -- they'll only be
+     * used for base interfaces of tested interfaces, return types, etc.
+     */
+    parsed_idls.forEach(function(parsed_idl)
+    {
+        if (parsed_idl.type == &quot;interface&quot; &amp;&amp; parsed_idl.partial)
+        {
+            this.partials.push(parsed_idl);
+            return;
+        }
+
+        if (parsed_idl.type == &quot;implements&quot;)
+        {
+            if (!(parsed_idl.target in this[&quot;implements&quot;]))
+            {
+                this[&quot;implements&quot;][parsed_idl.target] = [];
+            }
+            this[&quot;implements&quot;][parsed_idl.target].push(parsed_idl[&quot;implements&quot;]);
+            return;
+        }
+
+        parsed_idl.array = this;
+        if (parsed_idl.name in this.members)
+        {
+            throw &quot;Duplicate identifier &quot; + parsed_idl.name;
+        }
+        switch(parsed_idl.type)
+        {
+        case &quot;interface&quot;:
+            this.members[parsed_idl.name] =
+                new IdlInterface(parsed_idl, /* is_callback = */ false);
+            break;
+
+        case &quot;dictionary&quot;:
+            // Nothing to test, but we need the dictionary info around for type
+            // checks
+            this.members[parsed_idl.name] = new IdlDictionary(parsed_idl);
+            break;
+
+        case &quot;typedef&quot;:
+            this.members[parsed_idl.name] = new IdlTypedef(parsed_idl);
+            break;
+
+        case &quot;callback&quot;:
+            // TODO
+            console.log(&quot;callback not yet supported&quot;);
+            break;
+
+        case &quot;enum&quot;:
+            this.members[parsed_idl.name] = new IdlEnum(parsed_idl);
+            break;
+
+        case &quot;callback interface&quot;:
+            this.members[parsed_idl.name] =
+                new IdlInterface(parsed_idl, /* is_callback = */ true);
+            break;
+
+        default:
+            throw parsed_idl.name + &quot;: &quot; + parsed_idl.type + &quot; not yet supported&quot;;
+        }
+    }.bind(this));
+};
+
+//@}
+IdlArray.prototype.add_objects = function(dict)
+//@{
+{
+    /** Entry point.  See documentation at beginning of file. */
+    for (var k in dict)
+    {
+        if (k in this.objects)
+        {
+            this.objects[k] = this.objects[k].concat(dict[k]);
+        }
+        else
+        {
+            this.objects[k] = dict[k];
+        }
+    }
+};
+
+//@}
+IdlArray.prototype.prevent_multiple_testing = function(name)
+//@{
+{
+    /** Entry point.  See documentation at beginning of file. */
+    this.members[name].prevent_multiple_testing = true;
+};
+
+//@}
+IdlArray.prototype.recursively_get_implements = function(interface_name)
+//@{
+{
+    /**
+     * Helper function for test().  Returns an array of things that implement
+     * interface_name, so if the IDL contains
+     *
+     *   A implements B;
+     *   B implements C;
+     *   B implements D;
+     *
+     * then recursively_get_implements(&quot;A&quot;) should return [&quot;B&quot;, &quot;C&quot;, &quot;D&quot;].
+     */
+    var ret = this[&quot;implements&quot;][interface_name];
+    if (ret === undefined)
+    {
+        return [];
+    }
+    for (var i = 0; i &lt; this[&quot;implements&quot;][interface_name].length; i++)
+    {
+        ret = ret.concat(this.recursively_get_implements(ret[i]));
+        if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i]))
+        {
+            throw &quot;Circular implements statements involving &quot; + ret[i];
+        }
+    }
+    return ret;
+};
+
+function exposed_in(globals) {
+    if ('document' in self) {
+        return globals.indexOf(&quot;Window&quot;) &gt;= 0;
+    }
+    if ('DedicatedWorkerGlobalScope' in self &amp;&amp;
+        self instanceof DedicatedWorkerGlobalScope) {
+        return globals.indexOf(&quot;Worker&quot;) &gt;= 0 ||
+               globals.indexOf(&quot;DedicatedWorker&quot;) &gt;= 0;
+    }
+    if ('SharedWorkerGlobalScope' in self &amp;&amp;
+        self instanceof SharedWorkerGlobalScope) {
+        return globals.indexOf(&quot;Worker&quot;) &gt;= 0 ||
+               globals.indexOf(&quot;SharedWorker&quot;) &gt;= 0;
+    }
+    if ('ServiceWorkerGlobalScope' in self &amp;&amp;
+        self instanceof ServiceWorkerGlobalScope) {
+        return globals.indexOf(&quot;Worker&quot;) &gt;= 0 ||
+               globals.indexOf(&quot;ServiceWorker&quot;) &gt;= 0;
+    }
+    throw &quot;Unexpected global object&quot;;
+}
+
+//@}
+IdlArray.prototype.test = function()
+//@{
+{
+    /** Entry point.  See documentation at beginning of file. */
+
+    // First merge in all the partial interfaces and implements statements we
+    // encountered.
+    this.partials.forEach(function(parsed_idl)
+    {
+        if (!(parsed_idl.name in this.members)
+        || !(this.members[parsed_idl.name] instanceof IdlInterface))
+        {
+            throw &quot;Partial interface &quot; + parsed_idl.name + &quot; with no original interface&quot;;
+        }
+        if (parsed_idl.extAttrs)
+        {
+            parsed_idl.extAttrs.forEach(function(extAttr)
+            {
+                this.members[parsed_idl.name].extAttrs.push(extAttr);
+            }.bind(this));
+        }
+        parsed_idl.members.forEach(function(member)
+        {
+            this.members[parsed_idl.name].members.push(new IdlInterfaceMember(member));
+        }.bind(this));
+    }.bind(this));
+    this.partials = [];
+
+    for (var lhs in this[&quot;implements&quot;])
+    {
+        this.recursively_get_implements(lhs).forEach(function(rhs)
+        {
+            var errStr = lhs + &quot; implements &quot; + rhs + &quot;, but &quot;;
+            if (!(lhs in this.members)) throw errStr + lhs + &quot; is undefined.&quot;;
+            if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + &quot; is not an interface.&quot;;
+            if (!(rhs in this.members)) throw errStr + rhs + &quot; is undefined.&quot;;
+            if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + &quot; is not an interface.&quot;;
+            this.members[rhs].members.forEach(function(member)
+            {
+                this.members[lhs].members.push(new IdlInterfaceMember(member));
+            }.bind(this));
+        }.bind(this));
+    }
+    this[&quot;implements&quot;] = {};
+
+    Object.getOwnPropertyNames(this.members).forEach(function(memberName) {
+        var member = this.members[memberName];
+        if (!(member instanceof IdlInterface)) {
+            return;
+        }
+
+        var exposed = member.extAttrs.filter(function(a) { return a.name == &quot;Exposed&quot; });
+        if (exposed.length &gt; 1) {
+            throw &quot;Unexpected Exposed extended attributes on &quot; + memberName + &quot;: &quot; + exposed;
+        }
+
+        var globals = exposed.length === 1
+                    ? exposed[0].rhs.value
+                    : [&quot;Window&quot;];
+        member.exposed = exposed_in(globals);
+    }.bind(this));
+
+    // Now run test() on every member, and test_object() for every object.
+    for (var name in this.members)
+    {
+        this.members[name].test();
+        if (name in this.objects)
+        {
+            this.objects[name].forEach(function(str)
+            {
+                this.members[name].test_object(str);
+            }.bind(this));
+        }
+    }
+};
+
+//@}
+IdlArray.prototype.assert_type_is = function(value, type)
+//@{
+{
+    /**
+     * Helper function that tests that value is an instance of type according
+     * to the rules of WebIDL.  value is any JavaScript value, and type is an
+     * object produced by WebIDLParser.js' &quot;type&quot; production.  That production
+     * is fairly elaborate due to the complexity of WebIDL's types, so it's
+     * best to look at the grammar to figure out what properties it might have.
+     */
+    if (type.idlType == &quot;any&quot;)
+    {
+        // No assertions to make
+        return;
+    }
+
+    if (type.nullable &amp;&amp; value === null)
+    {
+        // This is fine
+        return;
+    }
+
+    if (type.array)
+    {
+        // TODO: not supported yet
+        return;
+    }
+
+    if (type.sequence)
+    {
+        assert_true(Array.isArray(value), &quot;is not array&quot;);
+        if (!value.length)
+        {
+            // Nothing we can do.
+            return;
+        }
+        this.assert_type_is(value[0], type.idlType.idlType);
+        return;
+    }
+
+    type = type.idlType;
+
+    switch(type)
+    {
+        case &quot;void&quot;:
+            assert_equals(value, undefined);
+            return;
+
+        case &quot;boolean&quot;:
+            assert_equals(typeof value, &quot;boolean&quot;);
+            return;
+
+        case &quot;byte&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_equals(value, Math.floor(value), &quot;not an integer&quot;);
+            assert_true(-128 &lt;= value &amp;&amp; value &lt;= 127, &quot;byte &quot; + value + &quot; not in range [-128, 127]&quot;);
+            return;
+
+        case &quot;octet&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_equals(value, Math.floor(value), &quot;not an integer&quot;);
+            assert_true(0 &lt;= value &amp;&amp; value &lt;= 255, &quot;octet &quot; + value + &quot; not in range [0, 255]&quot;);
+            return;
+
+        case &quot;short&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_equals(value, Math.floor(value), &quot;not an integer&quot;);
+            assert_true(-32768 &lt;= value &amp;&amp; value &lt;= 32767, &quot;short &quot; + value + &quot; not in range [-32768, 32767]&quot;);
+            return;
+
+        case &quot;unsigned short&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_equals(value, Math.floor(value), &quot;not an integer&quot;);
+            assert_true(0 &lt;= value &amp;&amp; value &lt;= 65535, &quot;unsigned short &quot; + value + &quot; not in range [0, 65535]&quot;);
+            return;
+
+        case &quot;long&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_equals(value, Math.floor(value), &quot;not an integer&quot;);
+            assert_true(-2147483648 &lt;= value &amp;&amp; value &lt;= 2147483647, &quot;long &quot; + value + &quot; not in range [-2147483648, 2147483647]&quot;);
+            return;
+
+        case &quot;unsigned long&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_equals(value, Math.floor(value), &quot;not an integer&quot;);
+            assert_true(0 &lt;= value &amp;&amp; value &lt;= 4294967295, &quot;unsigned long &quot; + value + &quot; not in range [0, 4294967295]&quot;);
+            return;
+
+        case &quot;long long&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            return;
+
+        case &quot;unsigned long long&quot;:
+        case &quot;DOMTimeStamp&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_true(0 &lt;= value, &quot;unsigned long long is negative&quot;);
+            return;
+
+        case &quot;float&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_equals(value, fround(value), &quot;float rounded to 32-bit float should be itself&quot;);
+            assert_not_equals(value, Infinity);
+            assert_not_equals(value, -Infinity);
+            assert_not_equals(value, NaN);
+            return;
+
+        case &quot;DOMHighResTimeStamp&quot;:
+        case &quot;double&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_not_equals(value, Infinity);
+            assert_not_equals(value, -Infinity);
+            assert_not_equals(value, NaN);
+            return;
+
+        case &quot;unrestricted float&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            assert_equals(value, fround(value), &quot;unrestricted float rounded to 32-bit float should be itself&quot;);
+            return;
+
+        case &quot;unrestricted double&quot;:
+            assert_equals(typeof value, &quot;number&quot;);
+            return;
+
+        case &quot;DOMString&quot;:
+            assert_equals(typeof value, &quot;string&quot;);
+            return;
+
+        case &quot;ByteString&quot;:
+            assert_equals(typeof value, &quot;string&quot;);
+            assert_regexp_match(value, /^[\x00-\x7F]*$/);
+            return;
+
+        case &quot;USVString&quot;:
+            assert_equals(typeof value, &quot;string&quot;);
+            assert_regexp_match(value, /^([\x00-\ud7ff\ue000-\uffff]|[\ud800-\udbff][\udc00-\udfff])*$/);
+            return;
+
+        case &quot;object&quot;:
+            assert_true(typeof value == &quot;object&quot; || typeof value == &quot;function&quot;, &quot;wrong type: not object or function&quot;);
+            return;
+    }
+
+    if (!(type in this.members))
+    {
+        throw &quot;Unrecognized type &quot; + type;
+    }
+
+    if (this.members[type] instanceof IdlInterface)
+    {
+        // We don't want to run the full
+        // IdlInterface.prototype.test_instance_of, because that could result
+        // in an infinite loop.  TODO: This means we don't have tests for
+        // NoInterfaceObject interfaces, and we also can't test objects that
+        // come from another self.
+        assert_true(typeof value == &quot;object&quot; || typeof value == &quot;function&quot;, &quot;wrong type: not object or function&quot;);
+        if (value instanceof Object
+        &amp;&amp; !this.members[type].has_extended_attribute(&quot;NoInterfaceObject&quot;)
+        &amp;&amp; type in self)
+        {
+            assert_true(value instanceof self[type], &quot;not instanceof &quot; + type);
+        }
+    }
+    else if (this.members[type] instanceof IdlEnum)
+    {
+        assert_equals(typeof value, &quot;string&quot;);
+    }
+    else if (this.members[type] instanceof IdlDictionary)
+    {
+        // TODO: Test when we actually have something to test this on
+    }
+    else if (this.members[type] instanceof IdlTypedef)
+    {
+        // TODO: Test when we actually have something to test this on
+    }
+    else
+    {
+        throw &quot;Type &quot; + type + &quot; isn't an interface or dictionary&quot;;
+    }
+};
+//@}
+
+/// IdlObject ///
+function IdlObject() {}
+IdlObject.prototype.test = function()
+//@{
+{
+    /**
+     * By default, this does nothing, so no actual tests are run for IdlObjects
+     * that don't define any (e.g., IdlDictionary at the time of this writing).
+     */
+};
+
+//@}
+IdlObject.prototype.has_extended_attribute = function(name)
+//@{
+{
+    /**
+     * This is only meaningful for things that support extended attributes,
+     * such as interfaces, exceptions, and members.
+     */
+    return this.extAttrs.some(function(o)
+    {
+        return o.name == name;
+    });
+};
+
+//@}
+
+/// IdlDictionary ///
+// Used for IdlArray.prototype.assert_type_is
+function IdlDictionary(obj)
+//@{
+{
+    /**
+     * obj is an object produced by the WebIDLParser.js &quot;dictionary&quot;
+     * production.
+     */
+
+    /** Self-explanatory. */
+    this.name = obj.name;
+
+    /** An array of objects produced by the &quot;dictionaryMember&quot; production. */
+    this.members = obj.members;
+
+    /**
+     * The name (as a string) of the dictionary type we inherit from, or null
+     * if there is none.
+     */
+    this.base = obj.inheritance;
+}
+
+//@}
+IdlDictionary.prototype = Object.create(IdlObject.prototype);
+
+/// IdlInterface ///
+function IdlInterface(obj, is_callback) {
+    /**
+     * obj is an object produced by the WebIDLParser.js &quot;interface&quot; production.
+     */
+
+    /** Self-explanatory. */
+    this.name = obj.name;
+
+    /** A back-reference to our IdlArray. */
+    this.array = obj.array;
+
+    /**
+     * An indicator of whether we should run tests on the interface object and
+     * interface prototype object. Tests on members are controlled by .untested
+     * on each member, not this.
+     */
+    this.untested = obj.untested;
+
+    /** An array of objects produced by the &quot;ExtAttr&quot; production. */
+    this.extAttrs = obj.extAttrs;
+
+    /** An array of IdlInterfaceMembers. */
+    this.members = obj.members.map(function(m){return new IdlInterfaceMember(m); });
+    if (this.has_extended_attribute(&quot;Unforgeable&quot;)) {
+        this.members
+            .filter(function(m) { return !m[&quot;static&quot;] &amp;&amp; (m.type == &quot;attribute&quot; || m.type == &quot;operation&quot;); })
+            .forEach(function(m) { return m.isUnforgeable = true; });
+    }
+
+    /**
+     * The name (as a string) of the type we inherit from, or null if there is
+     * none.
+     */
+    this.base = obj.inheritance;
+
+    this._is_callback = is_callback;
+}
+IdlInterface.prototype = Object.create(IdlObject.prototype);
+IdlInterface.prototype.is_callback = function()
+//@{
+{
+    return this._is_callback;
+};
+//@}
+
+IdlInterface.prototype.has_constants = function()
+//@{
+{
+    return this.members.some(function(member) {
+        return member.type === &quot;const&quot;;
+    });
+};
+//@}
+
+IdlInterface.prototype.is_global = function()
+//@{
+{
+    return this.extAttrs.some(function(attribute) {
+        return attribute.name === &quot;Global&quot; ||
+               attribute.name === &quot;PrimaryGlobal&quot;;
+    });
+};
+//@}
+
+IdlInterface.prototype.test = function()
+//@{
+{
+    if (this.has_extended_attribute(&quot;NoInterfaceObject&quot;))
+    {
+        // No tests to do without an instance.  TODO: We should still be able
+        // to run tests on the prototype object, if we obtain one through some
+        // other means.
+        return;
+    }
+
+    if (!this.exposed) {
+        test(function() {
+            assert_false(this.name in self);
+        }.bind(this), this.name + &quot; interface: existence and properties of interface object&quot;);
+        return;
+    }
+
+    if (!this.untested)
+    {
+        // First test things to do with the exception/interface object and
+        // exception/interface prototype object.
+        this.test_self();
+    }
+    // Then test things to do with its members (constants, fields, attributes,
+    // operations, . . .).  These are run even if .untested is true, because
+    // members might themselves be marked as .untested.  This might happen to
+    // interfaces if the interface itself is untested but a partial interface
+    // that extends it is tested -- then the interface itself and its initial
+    // members will be marked as untested, but the members added by the partial
+    // interface are still tested.
+    this.test_members();
+};
+//@}
+
+IdlInterface.prototype.test_self = function()
+//@{
+{
+    test(function()
+    {
+        // This function tests WebIDL as of 2015-01-13.
+
+        // &quot;For every interface that is exposed in a given ECMAScript global
+        // environment and:
+        // * is a callback interface that has constants declared on it, or
+        // * is a non-callback interface that is not declared with the
+        //   [NoInterfaceObject] extended attribute,
+        // a corresponding property MUST exist on the ECMAScript global object.
+        // The name of the property is the identifier of the interface, and its
+        // value is an object called the interface object.
+        // The property has the attributes { [[Writable]]: true,
+        // [[Enumerable]]: false, [[Configurable]]: true }.&quot;
+        if (this.is_callback() &amp;&amp; !this.has_constants()) {
+            return;
+        }
+
+        // TODO: Should we test here that the property is actually writable
+        // etc., or trust getOwnPropertyDescriptor?
+        assert_own_property(self, this.name,
+                            &quot;self does not have own property &quot; + format_value(this.name));
+        var desc = Object.getOwnPropertyDescriptor(self, this.name);
+        assert_false(&quot;get&quot; in desc, &quot;self's property &quot; + format_value(this.name) + &quot; has getter&quot;);
+        assert_false(&quot;set&quot; in desc, &quot;self's property &quot; + format_value(this.name) + &quot; has setter&quot;);
+        assert_true(desc.writable, &quot;self's property &quot; + format_value(this.name) + &quot; is not writable&quot;);
+        assert_false(desc.enumerable, &quot;self's property &quot; + format_value(this.name) + &quot; is enumerable&quot;);
+        assert_true(desc.configurable, &quot;self's property &quot; + format_value(this.name) + &quot; is not configurable&quot;);
+
+        if (this.is_callback()) {
+            // &quot;The internal [[Prototype]] property of an interface object for
+            // a callback interface MUST be the Object.prototype object.&quot;
+            assert_equals(Object.getPrototypeOf(self[this.name]), Object.prototype,
+                          &quot;prototype of self's property &quot; + format_value(this.name) + &quot; is not Object.prototype&quot;);
+
+            return;
+        }
+
+        // &quot;The interface object for a given non-callback interface is a
+        // function object.&quot;
+        // &quot;If an object is defined to be a function object, then it has
+        // characteristics as follows:&quot;
+
+        // Its [[Prototype]] internal property is otherwise specified (see
+        // below).
+
+        // &quot;* Its [[Get]] internal property is set as described in ECMA-262
+        //    section 9.1.8.&quot;
+        // Not much to test for this.
+
+        // &quot;* Its [[Construct]] internal property is set as described in
+        //    ECMA-262 section 19.2.2.3.&quot;
+        // Tested below if no constructor is defined.  TODO: test constructors
+        // if defined.
+
+        // &quot;* Its @@hasInstance property is set as described in ECMA-262
+        //    section 19.2.3.8, unless otherwise specified.&quot;
+        // TODO
+
+        // ES6 (rev 30) 19.1.3.6:
+        // &quot;Else, if O has a [[Call]] internal method, then let builtinTag be
+        // &quot;Function&quot;.&quot;
+        assert_class_string(self[this.name], &quot;Function&quot;, &quot;class string of &quot; + this.name);
+
+        // &quot;The [[Prototype]] internal property of an interface object for a
+        // non-callback interface is determined as follows:&quot;
+        var prototype = Object.getPrototypeOf(self[this.name]);
+        if (this.base) {
+            // &quot;* If the interface inherits from some other interface, the
+            //    value of [[Prototype]] is the interface object for that other
+            //    interface.&quot;
+            var has_interface_object =
+                !this.array
+                     .members[this.base]
+                     .has_extended_attribute(&quot;NoInterfaceObject&quot;);
+            if (has_interface_object) {
+                assert_own_property(self, this.base,
+                                    'should inherit from ' + this.base +
+                                    ', but self has no such property');
+                assert_equals(prototype, self[this.base],
+                              'prototype of ' + this.name + ' is not ' +
+                              this.base);
+            }
+        } else {
+            // &quot;If the interface doesn't inherit from any other interface, the
+            // value of [[Prototype]] is %FunctionPrototype% ([ECMA-262],
+            // section 6.1.7.4).&quot;
+            assert_equals(prototype, Function.prototype,
+                          &quot;prototype of self's property &quot; + format_value(this.name) + &quot; is not Function.prototype&quot;);
+        }
+
+        if (!this.has_extended_attribute(&quot;Constructor&quot;)) {
+            // &quot;The internal [[Call]] method of the interface object behaves as
+            // follows . . .
+            //
+            // &quot;If I was not declared with a [Constructor] extended attribute,
+            // then throw a TypeError.&quot;
+            assert_throws(new TypeError(), function() {
+                self[this.name]();
+            }.bind(this), &quot;interface object didn't throw TypeError when called as a function&quot;);
+            assert_throws(new TypeError(), function() {
+                new self[this.name]();
+            }.bind(this), &quot;interface object didn't throw TypeError when called as a constructor&quot;);
+        }
+    }.bind(this), this.name + &quot; interface: existence and properties of interface object&quot;);
+
+    if (!this.is_callback()) {
+        test(function() {
+            // This function tests WebIDL as of 2014-10-25.
+            // https://heycam.github.io/webidl/#es-interface-call
+
+            assert_own_property(self, this.name,
+                                &quot;self does not have own property &quot; + format_value(this.name));
+
+            // &quot;Interface objects for non-callback interfaces MUST have a
+            // property named “length” with attributes { [[Writable]]: false,
+            // [[Enumerable]]: false, [[Configurable]]: true } whose value is
+            // a Number.&quot;
+            assert_own_property(self[this.name], &quot;length&quot;);
+            var desc = Object.getOwnPropertyDescriptor(self[this.name], &quot;length&quot;);
+            assert_false(&quot;get&quot; in desc, this.name + &quot;.length has getter&quot;);
+            assert_false(&quot;set&quot; in desc, this.name + &quot;.length has setter&quot;);
+            assert_false(desc.writable, this.name + &quot;.length is writable&quot;);
+            assert_false(desc.enumerable, this.name + &quot;.length is enumerable&quot;);
+            assert_true(desc.configurable, this.name + &quot;.length is not configurable&quot;);
+
+            var constructors = this.extAttrs
+                .filter(function(attr) { return attr.name == &quot;Constructor&quot;; });
+            var expected_length = minOverloadLength(constructors);
+            assert_equals(self[this.name].length, expected_length, &quot;wrong value for &quot; + this.name + &quot;.length&quot;);
+        }.bind(this), this.name + &quot; interface object length&quot;);
+    }
+
+    if (!this.is_callback() || this.has_constants()) {
+        test(function() {
+            // This function tests WebIDL as of 2015-11-17.
+            // https://heycam.github.io/webidl/#interface-object
+
+            assert_own_property(self, this.name,
+                                &quot;self does not have own property &quot; + format_value(this.name));
+
+            // &quot;All interface objects must have a property named “name” with
+            // attributes { [[Writable]]: false, [[Enumerable]]: false,
+            // [[Configurable]]: true } whose value is the identifier of the
+            // corresponding interface.&quot;
+
+            assert_own_property(self[this.name], &quot;name&quot;);
+            var desc = Object.getOwnPropertyDescriptor(self[this.name], &quot;name&quot;);
+            assert_false(&quot;get&quot; in desc, this.name + &quot;.name has getter&quot;);
+            assert_false(&quot;set&quot; in desc, this.name + &quot;.name has setter&quot;);
+            assert_false(desc.writable, this.name + &quot;.name is writable&quot;);
+            assert_false(desc.enumerable, this.name + &quot;.name is enumerable&quot;);
+            assert_true(desc.configurable, this.name + &quot;.name is not configurable&quot;);
+            assert_equals(self[this.name].name, this.name, &quot;wrong value for &quot; + this.name + &quot;.name&quot;);
+        }.bind(this), this.name + &quot; interface object name&quot;);
+    }
+
+    // TODO: Test named constructors if I find any interfaces that have them.
+
+    test(function()
+    {
+        // This function tests WebIDL as of 2015-01-21.
+        // https://heycam.github.io/webidl/#interface-object
+
+        if (this.is_callback() &amp;&amp; !this.has_constants()) {
+            return;
+        }
+
+        assert_own_property(self, this.name,
+                            &quot;self does not have own property &quot; + format_value(this.name));
+
+        if (this.is_callback()) {
+            assert_false(&quot;prototype&quot; in self[this.name],
+                         this.name + ' should not have a &quot;prototype&quot; property');
+            return;
+        }
+
+        // &quot;An interface object for a non-callback interface must have a
+        // property named “prototype” with attributes { [[Writable]]: false,
+        // [[Enumerable]]: false, [[Configurable]]: false } whose value is an
+        // object called the interface prototype object. This object has
+        // properties that correspond to the regular attributes and regular
+        // operations defined on the interface, and is described in more detail
+        // in section 4.5.4 below.&quot;
+        assert_own_property(self[this.name], &quot;prototype&quot;,
+                            'interface &quot;' + this.name + '&quot; does not have own property &quot;prototype&quot;');
+        var desc = Object.getOwnPropertyDescriptor(self[this.name], &quot;prototype&quot;);
+        assert_false(&quot;get&quot; in desc, this.name + &quot;.prototype has getter&quot;);
+        assert_false(&quot;set&quot; in desc, this.name + &quot;.prototype has setter&quot;);
+        assert_false(desc.writable, this.name + &quot;.prototype is writable&quot;);
+        assert_false(desc.enumerable, this.name + &quot;.prototype is enumerable&quot;);
+        assert_false(desc.configurable, this.name + &quot;.prototype is configurable&quot;);
+
+        // Next, test that the [[Prototype]] of the interface prototype object
+        // is correct. (This is made somewhat difficult by the existence of
+        // [NoInterfaceObject].)
+        // TODO: Aryeh thinks there's at least other place in this file where
+        //       we try to figure out if an interface prototype object is
+        //       correct. Consolidate that code.
+
+        // &quot;The interface prototype object for a given interface A must have an
+        // internal [[Prototype]] property whose value is returned from the
+        // following steps:
+        // &quot;If A is declared with the [Global] or [PrimaryGlobal] extended
+        // attribute, and A supports named properties, then return the named
+        // properties object for A, as defined in section 4.5.5 below.
+        // &quot;Otherwise, if A is declared to inherit from another interface, then
+        // return the interface prototype object for the inherited interface.
+        // &quot;Otherwise, if A is declared with the [ArrayClass] extended
+        // attribute, then return %ArrayPrototype% ([ECMA-262], section
+        // 6.1.7.4).
+        // &quot;Otherwise, return %ObjectPrototype% ([ECMA-262], section 6.1.7.4).
+        // ([ECMA-262], section 15.2.4).
+        if (this.name === &quot;Window&quot;) {
+            assert_class_string(Object.getPrototypeOf(self[this.name].prototype),
+                                'WindowProperties',
+                                'Class name for prototype of Window' +
+                                '.prototype is not &quot;WindowProperties&quot;');
+        } else {
+            var inherit_interface, inherit_interface_has_interface_object;
+            if (this.base) {
+                inherit_interface = this.base;
+                inherit_interface_has_interface_object =
+                    !this.array
+                         .members[inherit_interface]
+                         .has_extended_attribute(&quot;NoInterfaceObject&quot;);
+            } else if (this.has_extended_attribute('ArrayClass')) {
+                inherit_interface = 'Array';
+                inherit_interface_has_interface_object = true;
+            } else {
+                inherit_interface = 'Object';
+                inherit_interface_has_interface_object = true;
+            }
+            if (inherit_interface_has_interface_object) {
+                assert_own_property(self, inherit_interface,
+                                    'should inherit from ' + inherit_interface + ', but self has no such property');
+                assert_own_property(self[inherit_interface], 'prototype',
+                                    'should inherit from ' + inherit_interface + ', but that object has no &quot;prototype&quot; property');
+                assert_equals(Object.getPrototypeOf(self[this.name].prototype),
+                              self[inherit_interface].prototype,
+                              'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype');
+            } else {
+                // We can't test that we get the correct object, because this is the
+                // only way to get our hands on it. We only test that its class
+                // string, at least, is correct.
+                assert_class_string(Object.getPrototypeOf(self[this.name].prototype),
+                                    inherit_interface + 'Prototype',
+                                    'Class name for prototype of ' + this.name +
+                                    '.prototype is not &quot;' + inherit_interface + 'Prototype&quot;');
+            }
+        }
+
+        // &quot;The class string of an interface prototype object is the
+        // concatenation of the interface’s identifier and the string
+        // “Prototype”.&quot;
+        assert_class_string(self[this.name].prototype, this.name + &quot;Prototype&quot;,
+                            &quot;class string of &quot; + this.name + &quot;.prototype&quot;);
+        // String() should end up calling {}.toString if nothing defines a
+        // stringifier.
+        if (!this.has_stringifier()) {
+            assert_equals(String(self[this.name].prototype), &quot;[object &quot; + this.name + &quot;Prototype]&quot;,
+                    &quot;String(&quot; + this.name + &quot;.prototype)&quot;);
+        }
+    }.bind(this), this.name + &quot; interface: existence and properties of interface prototype object&quot;);
+
+    test(function()
+    {
+        if (this.is_callback() &amp;&amp; !this.has_constants()) {
+            return;
+        }
+
+        assert_own_property(self, this.name,
+                            &quot;self does not have own property &quot; + format_value(this.name));
+
+        if (this.is_callback()) {
+            assert_false(&quot;prototype&quot; in self[this.name],
+                         this.name + ' should not have a &quot;prototype&quot; property');
+            return;
+        }
+
+        assert_own_property(self[this.name], &quot;prototype&quot;,
+                            'interface &quot;' + this.name + '&quot; does not have own property &quot;prototype&quot;');
+
+        // &quot;If the [NoInterfaceObject] extended attribute was not specified on
+        // the interface, then the interface prototype object must also have a
+        // property named “constructor” with attributes { [[Writable]]: true,
+        // [[Enumerable]]: false, [[Configurable]]: true } whose value is a
+        // reference to the interface object for the interface.&quot;
+        assert_own_property(self[this.name].prototype, &quot;constructor&quot;,
+                            this.name + '.prototype does not have own property &quot;constructor&quot;');
+        var desc = Object.getOwnPropertyDescriptor(self[this.name].prototype, &quot;constructor&quot;);
+        assert_false(&quot;get&quot; in desc, this.name + &quot;.prototype.constructor has getter&quot;);
+        assert_false(&quot;set&quot; in desc, this.name + &quot;.prototype.constructor has setter&quot;);
+        assert_true(desc.writable, this.name + &quot;.prototype.constructor is not writable&quot;);
+        assert_false(desc.enumerable, this.name + &quot;.prototype.constructor is enumerable&quot;);
+        assert_true(desc.configurable, this.name + &quot;.prototype.constructor in not configurable&quot;);
+        assert_equals(self[this.name].prototype.constructor, self[this.name],
+                      this.name + '.prototype.constructor is not the same object as ' + this.name);
+    }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s &quot;constructor&quot; property');
+};
+
+//@}
+IdlInterface.prototype.test_member_const = function(member)
+//@{
+{
+    if (!this.has_constants()) {
+        throw &quot;Internal error: test_member_const called without any constants&quot;;
+    }
+
+    test(function()
+    {
+        assert_own_property(self, this.name,
+                            &quot;self does not have own property &quot; + format_value(this.name));
+
+        // &quot;For each constant defined on an interface A, there must be
+        // a corresponding property on the interface object, if it
+        // exists.&quot;
+        assert_own_property(self[this.name], member.name);
+        // &quot;The value of the property is that which is obtained by
+        // converting the constant’s IDL value to an ECMAScript
+        // value.&quot;
+        assert_equals(self[this.name][member.name], constValue(member.value),
+                      &quot;property has wrong value&quot;);
+        // &quot;The property has attributes { [[Writable]]: false,
+        // [[Enumerable]]: true, [[Configurable]]: false }.&quot;
+        var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);
+        assert_false(&quot;get&quot; in desc, &quot;property has getter&quot;);
+        assert_false(&quot;set&quot; in desc, &quot;property has setter&quot;);
+        assert_false(desc.writable, &quot;property is writable&quot;);
+        assert_true(desc.enumerable, &quot;property is not enumerable&quot;);
+        assert_false(desc.configurable, &quot;property is configurable&quot;);
+    }.bind(this), this.name + &quot; interface: constant &quot; + member.name + &quot; on interface object&quot;);
+
+    // &quot;In addition, a property with the same characteristics must
+    // exist on the interface prototype object.&quot;
+    test(function()
+    {
+        assert_own_property(self, this.name,
+                            &quot;self does not have own property &quot; + format_value(this.name));
+
+        if (this.is_callback()) {
+            assert_false(&quot;prototype&quot; in self[this.name],
+                         this.name + ' should not have a &quot;prototype&quot; property');
+            return;
+        }
+
+        assert_own_property(self[this.name], &quot;prototype&quot;,
+                            'interface &quot;' + this.name + '&quot; does not have own property &quot;prototype&quot;');
+
+        assert_own_property(self[this.name].prototype, member.name);
+        assert_equals(self[this.name].prototype[member.name], constValue(member.value),
+                      &quot;property has wrong value&quot;);
+        var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);
+        assert_false(&quot;get&quot; in desc, &quot;property has getter&quot;);
+        assert_false(&quot;set&quot; in desc, &quot;property has setter&quot;);
+        assert_false(desc.writable, &quot;property is writable&quot;);
+        assert_true(desc.enumerable, &quot;property is not enumerable&quot;);
+        assert_false(desc.configurable, &quot;property is configurable&quot;);
+    }.bind(this), this.name + &quot; interface: constant &quot; + member.name + &quot; on interface prototype object&quot;);
+};
+
+
+//@}
+IdlInterface.prototype.test_member_attribute = function(member)
+//@{
+{
+    test(function()
+    {
+        if (this.is_callback() &amp;&amp; !this.has_constants()) {
+            return;
+        }
+
+        assert_own_property(self, this.name,
+                            &quot;self does not have own property &quot; + format_value(this.name));
+        assert_own_property(self[this.name], &quot;prototype&quot;,
+                            'interface &quot;' + this.name + '&quot; does not have own property &quot;prototype&quot;');
+
+        if (member[&quot;static&quot;]) {
+            assert_own_property(self[this.name], member.name,
+                &quot;The interface object must have a property &quot; +
+                format_value(member.name));
+        } else if (this.is_global()) {
+            assert_own_property(self, member.name,
+                &quot;The global object must have a property &quot; +
+                format_value(member.name));
+            assert_false(member.name in self[this.name].prototype,
+                &quot;The prototype object must not have a property &quot; +
+                format_value(member.name));
+
+            var getter = Object.getOwnPropertyDescriptor(self, member.name).get;
+            assert_equals(typeof(getter), &quot;function&quot;,
+                          format_value(member.name) + &quot; must have a getter&quot;);
+
+            // Try/catch around the get here, since it can legitimately throw.
+            // If it does, we obviously can't check for equality with direct
+            // invocation of the getter.
+            var gotValue;
+            var propVal;
+            try {
+                propVal = self[member.name];
+                gotValue = true;
+            } catch (e) {
+                gotValue = false;
+            }
+            if (gotValue) {
+                assert_equals(propVal, getter.call(undefined),
+                              &quot;Gets on a global should not require an explicit this&quot;);
+            }
+
+            this.do_interface_attribute_asserts(self, member);
+        } else {
+            assert_true(member.name in self[this.name].prototype,
+                &quot;The prototype object must have a property &quot; +
+                format_value(member.name));
+
+            if (!member.has_extended_attribute(&quot;LenientThis&quot;)) {
+                assert_throws(new TypeError(), function() {
+                    self[this.name].prototype[member.name];
+                }.bind(this), &quot;getting property on prototype object must throw TypeError&quot;);
+            } else {
+                assert_equals(self[this.name].prototype[member.name], undefined,
+                              &quot;getting property on prototype object must return undefined&quot;);
+            }
+            this.do_interface_attribute_asserts(self[this.name].prototype, member);
+        }
+    }.bind(this), this.name + &quot; interface: attribute &quot; + member.name);
+};
+
+//@}
+IdlInterface.prototype.test_member_operation = function(member)
+//@{
+{
+    var a_test = async_test(this.name + &quot; interface: operation &quot; + member.name +
+                            &quot;(&quot; + member.arguments.map(
+                                function(m) {return m.idlType.idlType; } )
+                            +&quot;)&quot;);
+    a_test.step(function()
+    {
+        // This function tests WebIDL as of 2015-12-29.
+        // https://heycam.github.io/webidl/#es-operations
+
+        if (this.is_callback() &amp;&amp; !this.has_constants()) {
+            a_test.done();
+            return;
+        }
+
+        assert_own_property(self, this.name,
+                            &quot;self does not have own property &quot; + format_value(this.name));
+
+        if (this.is_callback()) {
+            assert_false(&quot;prototype&quot; in self[this.name],
+                         this.name + ' should not have a &quot;prototype&quot; property');
+            a_test.done();
+            return;
+        }
+
+        assert_own_property(self[this.name], &quot;prototype&quot;,
+                            'interface &quot;' + this.name + '&quot; does not have own property &quot;prototype&quot;');
+
+        // &quot;For each unique identifier of an exposed operation defined on the
+        // interface, there must exist a corresponding property, unless the
+        // effective overload set for that identifier and operation and with an
+        // argument count of 0 has no entries.&quot;
+
+        // TODO: Consider [Exposed].
+
+        // &quot;The location of the property is determined as follows:&quot;
+        var memberHolderObject;
+        // &quot;* If the operation is static, then the property exists on the
+        //    interface object.&quot;
+        if (member[&quot;static&quot;]) {
+            assert_own_property(self[this.name], member.name,
+                    &quot;interface object missing static operation&quot;);
+            memberHolderObject = self[this.name];
+        // &quot;* Otherwise, [...] if the interface was declared with the [Global]
+        //    or [PrimaryGlobal] extended attribute, then the property exists
+        //    on every object that implements the interface.&quot;
+        } else if (this.is_global()) {
+            assert_own_property(self, member.name,
+                    &quot;global object missing non-static operation&quot;);
+            memberHolderObject = self;
+        // &quot;* Otherwise, the property exists solely on the interface’s
+        //    interface prototype object.&quot;
+        } else {
+            assert_own_property(self[this.name].prototype, member.name,
+                    &quot;interface prototype object missing non-static operation&quot;);
+            memberHolderObject = self[this.name].prototype;
+        }
+        this.do_member_operation_asserts(memberHolderObject, member, a_test);
+    }.bind(this));
+};
+
+//@}
+IdlInterface.prototype.do_member_operation_asserts = function(memberHolderObject, member, a_test)
+//@{
+{
+    var done = a_test.done.bind(a_test);
+    var operationUnforgeable = member.isUnforgeable;
+    var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name);
+    // &quot;The property has attributes { [[Writable]]: B,
+    // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the
+    // operation is unforgeable on the interface, and true otherwise&quot;.
+    assert_false(&quot;get&quot; in desc, &quot;property has getter&quot;);
+    assert_false(&quot;set&quot; in desc, &quot;property has setter&quot;);
+    assert_equals(desc.writable, !operationUnforgeable,
+                  &quot;property should be writable if and only if not unforgeable&quot;);
+    assert_true(desc.enumerable, &quot;property is not enumerable&quot;);
+    assert_equals(desc.configurable, !operationUnforgeable,
+                  &quot;property should be configurable if and only if not unforgeable&quot;);
+    // &quot;The value of the property is a Function object whose
+    // behavior is as follows . . .&quot;
+    assert_equals(typeof memberHolderObject[member.name], &quot;function&quot;,
+                  &quot;property must be a function&quot;);
+    // &quot;The value of the Function object’s “length” property is
+    // a Number determined as follows:
+    // &quot;. . .
+    // &quot;Return the length of the shortest argument list of the
+    // entries in S.&quot;
+    assert_equals(memberHolderObject[member.name].length,
+        minOverloadLength(this.members.filter(function(m) {
+            return m.type == &quot;operation&quot; &amp;&amp; m.name == member.name;
+        })),
+        &quot;property has wrong .length&quot;);
+
+    // Make some suitable arguments
+    var args = member.arguments.map(function(arg) {
+        return create_suitable_object(arg.idlType);
+    });
+
+    // &quot;Let O be a value determined as follows:
+    // &quot;. . .
+    // &quot;Otherwise, throw a TypeError.&quot;
+    // This should be hit if the operation is not static, there is
+    // no [ImplicitThis] attribute, and the this value is null.
+    //
+    // TODO: We currently ignore the [ImplicitThis] case.  Except we manually
+    // check for globals, since otherwise we'll invoke window.close().  And we
+    // have to skip this test for anything that on the proto chain of &quot;self&quot;,
+    // since that does in fact have implicit-this behavior.
+    if (!member[&quot;static&quot;]) {
+        var cb;
+        if (!this.is_global() &amp;&amp;
+            memberHolderObject[member.name] != self[member.name])
+        {
+            cb = awaitNCallbacks(2, done);
+            throwOrReject(a_test, member, memberHolderObject[member.name], null, args,
+                          &quot;calling operation with this = null didn't throw TypeError&quot;, cb);
+        } else {
+            cb = awaitNCallbacks(1, done);
+        }
+
+        // &quot;. . . If O is not null and is also not a platform object
+        // that implements interface I, throw a TypeError.&quot;
+        //
+        // TODO: Test a platform object that implements some other
+        // interface.  (Have to be sure to get inheritance right.)
+        throwOrReject(a_test, member, memberHolderObject[member.name], {}, args,
+                      &quot;calling operation with this = {} didn't throw TypeError&quot;, cb);
+    } else {
+        done();
+    }
+}
+
+//@}
+IdlInterface.prototype.test_member_stringifier = function(member)
+//@{
+{
+    test(function()
+    {
+        if (this.is_callback() &amp;&amp; !this.has_constants()) {
+            return;
+        }
+
+        assert_own_property(self, this.name,
+                            &quot;self does not have own property &quot; + format_value(this.name));
+
+        if (this.is_callback()) {
+            assert_false(&quot;prototype&quot; in self[this.name],
+                         this.name + ' should not have a &quot;prototype&quot; property');
+            return;
+        }
+
+        assert_own_property(self[this.name], &quot;prototype&quot;,
+                            'interface &quot;' + this.name + '&quot; does not have own property &quot;prototype&quot;');
+
+        // &quot;. . . the property exists on the interface prototype object.&quot;
+        var interfacePrototypeObject = self[this.name].prototype;
+        assert_own_property(self[this.name].prototype, &quot;toString&quot;,
+                &quot;interface prototype object missing non-static operation&quot;);
+
+        var stringifierUnforgeable = member.isUnforgeable;
+        var desc = Object.getOwnPropertyDescriptor(interfacePrototypeObject, &quot;toString&quot;);
+        // &quot;The property has attributes { [[Writable]]: B,
+        // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the
+        // stringifier is unforgeable on the interface, and true otherwise.&quot;
+        assert_false(&quot;get&quot; in desc, &quot;property has getter&quot;);
+        assert_false(&quot;set&quot; in desc, &quot;property has setter&quot;);
+        assert_equals(desc.writable, !stringifierUnforgeable,
+                      &quot;property should be writable if and only if not unforgeable&quot;);
+        assert_true(desc.enumerable, &quot;property is not enumerable&quot;);
+        assert_equals(desc.configurable, !stringifierUnforgeable,
+                      &quot;property should be configurable if and only if not unforgeable&quot;);
+        // &quot;The value of the property is a Function object, which behaves as
+        // follows . . .&quot;
+        assert_equals(typeof interfacePrototypeObject.toString, &quot;function&quot;,
+                      &quot;property must be a function&quot;);
+        // &quot;The value of the Function object’s “length” property is the Number
+        // value 0.&quot;
+        assert_equals(interfacePrototypeObject.toString.length, 0,
+            &quot;property has wrong .length&quot;);
+
+        // &quot;Let O be the result of calling ToObject on the this value.&quot;
+        assert_throws(new TypeError(), function() {
+            self[this.name].prototype.toString.apply(null, []);
+        }, &quot;calling stringifier with this = null didn't throw TypeError&quot;);
+
+        // &quot;If O is not an object that implements the interface on which the
+        // stringifier was declared, then throw a TypeError.&quot;
+        //
+        // TODO: Test a platform object that implements some other
+        // interface.  (Have to be sure to get inheritance right.)
+        assert_throws(new TypeError(), function() {
+            self[this.name].prototype.toString.apply({}, []);
+        }, &quot;calling stringifier with this = {} didn't throw TypeError&quot;);
+    }.bind(this), this.name + &quot; interface: stringifier&quot;);
+};
+
+//@}
+IdlInterface.prototype.test_members = function()
+//@{
+{
+    for (var i = 0; i &lt; this.members.length; i++)
+    {
+        var member = this.members[i];
+        if (member.untested) {
+            continue;
+        }
+
+        switch (member.type) {
+        case &quot;const&quot;:
+            this.test_member_const(member);
+            break;
+
+        case &quot;attribute&quot;:
+            // For unforgeable attributes, we do the checks in
+            // test_interface_of instead.
+            if (!member.isUnforgeable)
+            {
+                this.test_member_attribute(member);
+            }
+            break;
+
+        case &quot;operation&quot;:
+            // TODO: Need to correctly handle multiple operations with the same
+            // identifier.
+            // For unforgeable operations, we do the checks in
+            // test_interface_of instead.
+            if (member.name) {
+                if (!member.isUnforgeable)
+                {
+                    this.test_member_operation(member);
+                }
+            } else if (member.stringifier) {
+                this.test_member_stringifier(member);
+            }
+            break;
+
+        default:
+            // TODO: check more member types.
+            break;
+        }
+    }
+};
+
+//@}
+IdlInterface.prototype.test_object = function(desc)
+//@{
+{
+    var obj, exception = null;
+    try
+    {
+        obj = eval(desc);
+    }
+    catch(e)
+    {
+        exception = e;
+    }
+
+    var expected_typeof =
+        this.members.some(function(member) { return member.legacycaller; })
+        ? &quot;function&quot;
+        : &quot;object&quot;;
+
+    this.test_primary_interface_of(desc, obj, exception, expected_typeof);
+    var current_interface = this;
+    while (current_interface)
+    {
+        if (!(current_interface.name in this.array.members))
+        {
+            throw &quot;Interface &quot; + current_interface.name + &quot; not found (inherited by &quot; + this.name + &quot;)&quot;;
+        }
+        if (current_interface.prevent_multiple_testing &amp;&amp; current_interface.already_tested)
+        {
+            return;
+        }
+        current_interface.test_interface_of(desc, obj, exception, expected_typeof);
+        current_interface = this.array.members[current_interface.base];
+    }
+};
+
+//@}
+IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception, expected_typeof)
+//@{
+{
+    // We can't easily test that its prototype is correct if there's no
+    // interface object, or the object is from a different global environment
+    // (not instanceof Object).  TODO: test in this case that its prototype at
+    // least looks correct, even if we can't test that it's actually correct.
+    if (!this.has_extended_attribute(&quot;NoInterfaceObject&quot;)
+    &amp;&amp; (typeof obj != expected_typeof || obj instanceof Object))
+    {
+        test(function()
+        {
+            assert_equals(exception, null, &quot;Unexpected exception when evaluating object&quot;);
+            assert_equals(typeof obj, expected_typeof, &quot;wrong typeof object&quot;);
+            assert_own_property(self, this.name,
+                                &quot;self does not have own property &quot; + format_value(this.name));
+            assert_own_property(self[this.name], &quot;prototype&quot;,
+                                'interface &quot;' + this.name + '&quot; does not have own property &quot;prototype&quot;');
+
+            // &quot;The value of the internal [[Prototype]] property of the
+            // platform object is the interface prototype object of the primary
+            // interface from the platform object’s associated global
+            // environment.&quot;
+            assert_equals(Object.getPrototypeOf(obj),
+                          self[this.name].prototype,
+                          desc + &quot;'s prototype is not &quot; + this.name + &quot;.prototype&quot;);
+        }.bind(this), this.name + &quot; must be primary interface of &quot; + desc);
+    }
+
+    // &quot;The class string of a platform object that implements one or more
+    // interfaces must be the identifier of the primary interface of the
+    // platform object.&quot;
+    test(function()
+    {
+        assert_equals(exception, null, &quot;Unexpected exception when evaluating object&quot;);
+        assert_equals(typeof obj, expected_typeof, &quot;wrong typeof object&quot;);
+        assert_class_string(obj, this.name, &quot;class string of &quot; + desc);
+        if (!this.has_stringifier())
+        {
+            assert_equals(String(obj), &quot;[object &quot; + this.name + &quot;]&quot;, &quot;String(&quot; + desc + &quot;)&quot;);
+        }
+    }.bind(this), &quot;Stringification of &quot; + desc);
+};
+
+//@}
+IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expected_typeof)
+//@{
+{
+    // TODO: Indexed and named properties, more checks on interface members
+    this.already_tested = true;
+
+    for (var i = 0; i &lt; this.members.length; i++)
+    {
+        var member = this.members[i];
+        if (member.type == &quot;attribute&quot; &amp;&amp; member.isUnforgeable)
+        {
+            test(function()
+            {
+                assert_equals(exception, null, &quot;Unexpected exception when evaluating object&quot;);
+                assert_equals(typeof obj, expected_typeof, &quot;wrong typeof object&quot;);
+                this.do_interface_attribute_asserts(obj, member);
+            }.bind(this), this.name + &quot; interface: &quot; + desc + ' must have own property &quot;' + member.name + '&quot;');
+        }
+        else if (member.type == &quot;operation&quot; &amp;&amp;
+                 member.name &amp;&amp;
+                 member.isUnforgeable)
+        {
+            var a_test = async_test(this.name + &quot; interface: &quot; + desc + ' must have own property &quot;' + member.name + '&quot;');
+            a_test.step(function()
+            {
+                assert_equals(exception, null, &quot;Unexpected exception when evaluating object&quot;);
+                assert_equals(typeof obj, expected_typeof, &quot;wrong typeof object&quot;);
+                assert_own_property(obj, member.name,
+                                    &quot;Doesn't have the unforgeable operation property&quot;);
+                this.do_member_operation_asserts(obj, member, a_test);
+            }.bind(this));
+        }
+        else if ((member.type == &quot;const&quot;
+        || member.type == &quot;attribute&quot;
+        || member.type == &quot;operation&quot;)
+        &amp;&amp; member.name)
+        {
+            test(function()
+            {
+                assert_equals(exception, null, &quot;Unexpected exception when evaluating object&quot;);
+                assert_equals(typeof obj, expected_typeof, &quot;wrong typeof object&quot;);
+                if (!member[&quot;static&quot;]) {
+                    if (!this.is_global()) {
+                        assert_inherits(obj, member.name);
+                    } else {
+                        assert_own_property(obj, member.name);
+                    }
+
+                    if (member.type == &quot;const&quot;)
+                    {
+                        assert_equals(obj[member.name], constValue(member.value));
+                    }
+                    if (member.type == &quot;attribute&quot;)
+                    {
+                        // Attributes are accessor properties, so they might
+                        // legitimately throw an exception rather than returning
+                        // anything.
+                        var property, thrown = false;
+                        try
+                        {
+                            property = obj[member.name];
+                        }
+                        catch (e)
+                        {
+                            thrown = true;
+                        }
+                        if (!thrown)
+                        {
+                            this.array.assert_type_is(property, member.idlType);
+                        }
+                    }
+                    if (member.type == &quot;operation&quot;)
+                    {
+                        assert_equals(typeof obj[member.name], &quot;function&quot;);
+                    }
+                }
+            }.bind(this), this.name + &quot; interface: &quot; + desc + ' must inherit property &quot;' + member.name + '&quot; with the proper type (' + i + ')');
+        }
+        // TODO: This is wrong if there are multiple operations with the same
+        // identifier.
+        // TODO: Test passing arguments of the wrong type.
+        if (member.type == &quot;operation&quot; &amp;&amp; member.name &amp;&amp; member.arguments.length)
+        {
+            var a_test = async_test( this.name + &quot; interface: calling &quot; + member.name +
+            &quot;(&quot; + member.arguments.map(function(m) { return m.idlType.idlType; }) +
+            &quot;) on &quot; + desc + &quot; with too few arguments must throw TypeError&quot;);
+            a_test.step(function()
+            {
+                assert_equals(exception, null, &quot;Unexpected exception when evaluating object&quot;);
+                assert_equals(typeof obj, expected_typeof, &quot;wrong typeof object&quot;);
+                if (!member[&quot;static&quot;]) {
+                    if (!this.is_global() &amp;&amp; !member.isUnforgeable) {
+                        assert_inherits(obj, member.name);
+                    } else {
+                        assert_own_property(obj, member.name);
+                    }
+                }
+                else
+                {
+                    assert_false(member.name in obj);
+                }
+
+                var minLength = minOverloadLength(this.members.filter(function(m) {
+                    return m.type == &quot;operation&quot; &amp;&amp; m.name == member.name;
+                }));
+                var args = [];
+                var cb = awaitNCallbacks(minLength, a_test.done.bind(a_test));
+                for (var i = 0; i &lt; minLength; i++) {
+                    throwOrReject(a_test, member, obj[member.name], obj, args,  &quot;Called with &quot; + i + &quot; arguments&quot;, cb);
+
+                    args.push(create_suitable_object(member.arguments[i].idlType));
+                }
+                if (minLength === 0) {
+                    cb();
+                }
+            }.bind(this));
+        }
+    }
+};
+
+//@}
+IdlInterface.prototype.has_stringifier = function()
+//@{
+{
+    if (this.members.some(function(member) { return member.stringifier; })) {
+        return true;
+    }
+    if (this.base &amp;&amp;
+        this.array.members[this.base].has_stringifier()) {
+        return true;
+    }
+    return false;
+};
+
+//@}
+IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member)
+//@{
+{
+    // This function tests WebIDL as of 2015-01-27.
+    // TODO: Consider [Exposed].
+
+    // This is called by test_member_attribute() with the prototype as obj if
+    // it is not a global, and the global otherwise, and by test_interface_of()
+    // with the object as obj.
+
+    // &quot;For each exposed attribute of the interface, whether it was declared on
+    // the interface itself or one of its consequential interfaces, there MUST
+    // exist a corresponding property. The characteristics of this property are
+    // as follows:&quot;
+
+    // &quot;The name of the property is the identifier of the attribute.&quot;
+    assert_own_property(obj, member.name);
+
+    // &quot;The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]:
+    // true, [[Configurable]]: configurable }, where:
+    // &quot;configurable is false if the attribute was declared with the
+    // [Unforgeable] extended attribute and true otherwise;
+    // &quot;G is the attribute getter, defined below; and
+    // &quot;S is the attribute setter, also defined below.&quot;
+    var desc = Object.getOwnPropertyDescriptor(obj, member.name);
+    assert_false(&quot;value&quot; in desc, 'property descriptor has value but is supposed to be accessor');
+    assert_false(&quot;writable&quot; in desc, 'property descriptor has &quot;writable&quot; field but is supposed to be accessor');
+    assert_true(desc.enumerable, &quot;property is not enumerable&quot;);
+    if (member.isUnforgeable)
+    {
+        assert_false(desc.configurable, &quot;[Unforgeable] property must not be configurable&quot;);
+    }
+    else
+    {
+        assert_true(desc.configurable, &quot;property must be configurable&quot;);
+    }
+
+
+    // &quot;The attribute getter is a Function object whose behavior when invoked
+    // is as follows:&quot;
+    assert_equals(typeof desc.get, &quot;function&quot;, &quot;getter must be Function&quot;);
+
+    // &quot;If the attribute is a regular attribute, then:&quot;
+    if (!member[&quot;static&quot;]) {
+        // &quot;If O is not a platform object that implements I, then:
+        // &quot;If the attribute was specified with the [LenientThis] extended
+        // attribute, then return undefined.
+        // &quot;Otherwise, throw a TypeError.&quot;
+        if (!member.has_extended_attribute(&quot;LenientThis&quot;)) {
+            assert_throws(new TypeError(), function() {
+                desc.get.call({});
+            }.bind(this), &quot;calling getter on wrong object type must throw TypeError&quot;);
+        } else {
+            assert_equals(desc.get.call({}), undefined,
+                          &quot;calling getter on wrong object type must return undefined&quot;);
+        }
+    }
+
+    // &quot;The value of the Function object’s “length” property is the Number
+    // value 0.&quot;
+    assert_equals(desc.get.length, 0, &quot;getter length must be 0&quot;);
+
+
+    // TODO: Test calling setter on the interface prototype (should throw
+    // TypeError in most cases).
+    if (member.readonly
+    &amp;&amp; !member.has_extended_attribute(&quot;PutForwards&quot;)
+    &amp;&amp; !member.has_extended_attribute(&quot;Replaceable&quot;))
+    {
+        // &quot;The attribute setter is undefined if the attribute is declared
+        // readonly and has neither a [PutForwards] nor a [Replaceable]
+        // extended attribute declared on it.&quot;
+        assert_equals(desc.set, undefined, &quot;setter must be undefined for readonly attributes&quot;);
+    }
+    else
+    {
+        // &quot;Otherwise, it is a Function object whose behavior when
+        // invoked is as follows:&quot;
+        assert_equals(typeof desc.set, &quot;function&quot;, &quot;setter must be function for PutForwards, Replaceable, or non-readonly attributes&quot;);
+
+        // &quot;If the attribute is a regular attribute, then:&quot;
+        if (!member[&quot;static&quot;]) {
+            // &quot;If /validThis/ is false and the attribute was not specified
+            // with the [LenientThis] extended attribute, then throw a
+            // TypeError.&quot;
+            // &quot;If the attribute is declared with a [Replaceable] extended
+            // attribute, then: ...&quot;
+            // &quot;If validThis is false, then return.&quot;
+            if (!member.has_extended_attribute(&quot;LenientThis&quot;)) {
+                assert_throws(new TypeError(), function() {
+                    desc.set.call({});
+                }.bind(this), &quot;calling setter on wrong object type must throw TypeError&quot;);
+            } else {
+                assert_equals(desc.set.call({}), undefined,
+                              &quot;calling setter on wrong object type must return undefined&quot;);
+            }
+        }
+
+        // &quot;The value of the Function object’s “length” property is the Number
+        // value 1.&quot;
+        assert_equals(desc.set.length, 1, &quot;setter length must be 1&quot;);
+    }
+}
+//@}
+
+/// IdlInterfaceMember ///
+function IdlInterfaceMember(obj)
+//@{
+{
+    /**
+     * obj is an object produced by the WebIDLParser.js &quot;ifMember&quot; production.
+     * We just forward all properties to this object without modification,
+     * except for special extAttrs handling.
+     */
+    for (var k in obj)
+    {
+        this[k] = obj[k];
+    }
+    if (!(&quot;extAttrs&quot; in this))
+    {
+        this.extAttrs = [];
+    }
+
+    this.isUnforgeable = this.has_extended_attribute(&quot;Unforgeable&quot;);
+}
+
+//@}
+IdlInterfaceMember.prototype = Object.create(IdlObject.prototype);
+
+/// Internal helper functions ///
+function create_suitable_object(type)
+//@{
+{
+    /**
+     * type is an object produced by the WebIDLParser.js &quot;type&quot; production.  We
+     * return a JavaScript value that matches the type, if we can figure out
+     * how.
+     */
+    if (type.nullable)
+    {
+        return null;
+    }
+    switch (type.idlType)
+    {
+        case &quot;any&quot;:
+        case &quot;boolean&quot;:
+            return true;
+
+        case &quot;byte&quot;: case &quot;octet&quot;: case &quot;short&quot;: case &quot;unsigned short&quot;:
+        case &quot;long&quot;: case &quot;unsigned long&quot;: case &quot;long long&quot;:
+        case &quot;unsigned long long&quot;: case &quot;float&quot;: case &quot;double&quot;:
+        case &quot;unrestricted float&quot;: case &quot;unrestricted double&quot;:
+            return 7;
+
+        case &quot;DOMString&quot;:
+        case &quot;ByteString&quot;:
+        case &quot;USVString&quot;:
+            return &quot;foo&quot;;
+
+        case &quot;object&quot;:
+            return {a: &quot;b&quot;};
+
+        case &quot;Node&quot;:
+            return document.createTextNode(&quot;abc&quot;);
+    }
+    return null;
+}
+//@}
+
+/// IdlEnum ///
+// Used for IdlArray.prototype.assert_type_is
+function IdlEnum(obj)
+//@{
+{
+    /**
+     * obj is an object produced by the WebIDLParser.js &quot;dictionary&quot;
+     * production.
+     */
+
+    /** Self-explanatory. */
+    this.name = obj.name;
+
+    /** An array of values produced by the &quot;enum&quot; production. */
+    this.values = obj.values;
+
+}
+//@}
+
+IdlEnum.prototype = Object.create(IdlObject.prototype);
+
+/// IdlTypedef ///
+// Used for IdlArray.prototype.assert_type_is
+function IdlTypedef(obj)
+//@{
+{
+    /**
+     * obj is an object produced by the WebIDLParser.js &quot;typedef&quot;
+     * production.
+     */
+
+    /** Self-explanatory. */
+    this.name = obj.name;
+
+    /** An array of values produced by the &quot;typedef&quot; production. */
+    this.values = obj.values;
+
+}
+//@}
+
+IdlTypedef.prototype = Object.create(IdlObject.prototype);
+
+}());
+// vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker:
</ins></span></pre>
</div>
</div>

</body>
</html>