mirror of
https://github.com/servo/servo.git
synced 2025-08-18 11:55:39 +01:00
Update web-platform-tests to revision 0d318188757a9c996e20b82db201fd04de5aa255
This commit is contained in:
parent
b2a5225831
commit
1a81b18b9f
12321 changed files with 544385 additions and 6 deletions
3
tests/wpt/web-platform-tests/resources/.gitignore
vendored
Normal file
3
tests/wpt/web-platform-tests/resources/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
ROBIN-TODO.txt
|
||||
scratch
|
||||
node_modules
|
3
tests/wpt/web-platform-tests/resources/.gitmodules
vendored
Normal file
3
tests/wpt/web-platform-tests/resources/.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "webidl2"]
|
||||
path = webidl2
|
||||
url = https://github.com/darobin/webidl2.js.git
|
2
tests/wpt/web-platform-tests/resources/.htaccess
Normal file
2
tests/wpt/web-platform-tests/resources/.htaccess
Normal file
|
@ -0,0 +1,2 @@
|
|||
# make tests that use utf-16 not inherit the encoding for testharness.js et. al.
|
||||
AddCharset utf-8 .css .js
|
|
@ -0,0 +1,3 @@
|
|||
importScripts("testharness.js");
|
||||
|
||||
throw new Error("This failure is expected.");
|
34
tests/wpt/web-platform-tests/resources/apisample-worker.js
Normal file
34
tests/wpt/web-platform-tests/resources/apisample-worker.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
importScripts("testharness.js");
|
||||
|
||||
test(
|
||||
function(test) {
|
||||
assert_true(true, "True is true");
|
||||
},
|
||||
"Worker test that completes successfully");
|
||||
|
||||
test(
|
||||
function(test) {
|
||||
assert_true(false, "Failing test");
|
||||
},
|
||||
"Worker test that fails ('FAIL')");
|
||||
|
||||
async_test(
|
||||
function(test) {
|
||||
assert_true(true, "True is true");
|
||||
},
|
||||
"Worker test that times out ('TIMEOUT')");
|
||||
|
||||
async_test("Worker test that doesn't run ('NOT RUN')");
|
||||
|
||||
async_test(
|
||||
function(test) {
|
||||
self.setTimeout(
|
||||
function() {
|
||||
test.done();
|
||||
},
|
||||
0);
|
||||
},
|
||||
"Worker async_test that completes successfully");
|
||||
|
||||
// An explicit done() is required for dedicated and shared web workers.
|
||||
done();
|
175
tests/wpt/web-platform-tests/resources/apisample.htm
Normal file
175
tests/wpt/web-platform-tests/resources/apisample.htm
Normal file
|
@ -0,0 +1,175 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Sample HTML5 API Tests</title>
|
||||
<meta name="timeout" content="6000">
|
||||
</head>
|
||||
<body onload="load_test_attr.done()">
|
||||
<h1>Sample HTML5 API Tests</h1>
|
||||
<div id="log"></div>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
<script>
|
||||
setup_run = false;
|
||||
setup(function() {
|
||||
setup_run = true;
|
||||
});
|
||||
test(function() {assert_true(setup_run)}, "Setup function ran");
|
||||
|
||||
// Two examples for testing events from handler and attributes
|
||||
var load_test_event = async_test("window onload event fires when set from the handler");
|
||||
|
||||
function windowLoad()
|
||||
{
|
||||
load_test_event.done();
|
||||
}
|
||||
on_event(window, "load", windowLoad);
|
||||
|
||||
// see the body onload below
|
||||
var load_test_attr = async_test("body element fires the onload event set from the attribute");
|
||||
</script>
|
||||
<script>
|
||||
function bodyElement()
|
||||
{
|
||||
assert_equals(document.body, document.getElementsByTagName("body")[0]);
|
||||
}
|
||||
test(bodyElement, "document.body should be the first body element in the document");
|
||||
|
||||
test(function() {
|
||||
assert_equals(1,1);
|
||||
assert_equals(NaN, NaN, "NaN case");
|
||||
assert_equals(0, 0, "Zero case");
|
||||
}, "assert_equals tests")
|
||||
|
||||
test(function() {
|
||||
assert_equals(-0, 0, "Zero case");
|
||||
}, "assert_equals tests expected to fail")
|
||||
|
||||
test(function() {
|
||||
assert_not_equals({}, {}, "object case");
|
||||
assert_not_equals(-0, 0, "Zero case");
|
||||
}, "assert_not_equals tests")
|
||||
|
||||
function testAssertPass()
|
||||
{
|
||||
assert_true(true);
|
||||
}
|
||||
test(testAssertPass, "assert_true expected to pass");
|
||||
|
||||
function testAssertFalse()
|
||||
{
|
||||
assert_true(false, "false should not be true");
|
||||
}
|
||||
test(testAssertFalse, "assert_true expected to fail");
|
||||
|
||||
function basicAssertArrayEquals()
|
||||
{
|
||||
assert_array_equals([1, NaN], [1, NaN], "[1, NaN] is equal to [1, NaN]");
|
||||
}
|
||||
test(basicAssertArrayEquals, "basic assert_array_equals test");
|
||||
|
||||
function basicAssertObjectEquals()
|
||||
{
|
||||
assert_object_equals([1, 2, [1, 2]], { 0: 1, 1: 2, 2: { 0: 1, 1: 2} }, "array is equal to object")
|
||||
}
|
||||
test(basicAssertObjectEquals, "basic assert_object_equals test");
|
||||
|
||||
function basicAssertApproxEquals()
|
||||
{
|
||||
assert_approx_equals(10, 11, 1, "10 is approximately (+/- 1) 11")
|
||||
}
|
||||
test(basicAssertApproxEquals, "basic assert_approx_equals test");
|
||||
|
||||
function basicAssertLessThan()
|
||||
{
|
||||
assert_less_than(10, 11, "10 is less than 11")
|
||||
}
|
||||
test(basicAssertApproxEquals, "basic assert_less_than test");
|
||||
|
||||
function basicAssertGreaterThan()
|
||||
{
|
||||
assert_greater_than(10, 11, "10 is not greater than 11");
|
||||
}
|
||||
test(basicAssertGreaterThan, "assert_greater_than expected to fail");
|
||||
|
||||
function basicAssertGreaterThanEqual()
|
||||
{
|
||||
assert_greater_than_equal(10, 10, "10 is greater than or equal to 10")
|
||||
}
|
||||
test(basicAssertGreaterThanEqual, "basic assert_greater_than_equal test");
|
||||
|
||||
function basicAssertLessThanEqual()
|
||||
{
|
||||
assert_greater_than_equal('10', 10, "'10' is not a number")
|
||||
}
|
||||
test(basicAssertLessThanEqual, "assert_less_than_equal expected to fail");
|
||||
|
||||
function testAssertInherits() {
|
||||
var A = function(){this.a = "a"}
|
||||
A.prototype = {b:"b"}
|
||||
var a = new A();
|
||||
assert_exists(a, "a");
|
||||
assert_not_exists(a, "b");
|
||||
assert_inherits(a, "b");
|
||||
}
|
||||
test(testAssertInherits, "test for assert[_not]_exists and insert_inherits")
|
||||
|
||||
test(function()
|
||||
{
|
||||
var a = document.createElement("a")
|
||||
var b = document.createElement("b")
|
||||
assert_throws("NOT_FOUND_ERR", function(){a.removeChild(b)});
|
||||
}, "Test throw DOM exception")
|
||||
|
||||
test(function()
|
||||
{
|
||||
var a = document.createTextNode("a")
|
||||
var b = document.createElement("b")
|
||||
assert_throws("NOT_FOUND_ERR", function(){a.appendChild(b)});
|
||||
}, "Test throw DOM exception expected to fail")
|
||||
|
||||
test(function()
|
||||
{
|
||||
var e = {code:0, name:"TEST_ERR", TEST_ERR:0}
|
||||
assert_throws("TEST_ERR", function() {throw e});
|
||||
}, "Test assert_throws with non-DOM-exception expected to Fail");
|
||||
|
||||
var t = async_test("Test step_func")
|
||||
setTimeout(
|
||||
t.step_func(
|
||||
function () {
|
||||
assert_true(true); t.done();
|
||||
}), 0);
|
||||
|
||||
async_test(function(t) {
|
||||
setTimeout(t.step_func(function (){assert_true(true); t.done();}), 0);
|
||||
}, "Test async test with callback");
|
||||
|
||||
async_test(function() {
|
||||
setTimeout(this.step_func(function (){assert_true(true); this.done();}), 0);
|
||||
}, "Test async test with callback and `this` obj.");
|
||||
|
||||
async_test("test should timeout (fail) with the default of 2 seconds").step(function(){});
|
||||
|
||||
async_test("test should timeout (fail) with a custom set timeout value of 1 second",
|
||||
{timeout:1000}).step(function(){});
|
||||
|
||||
async_test("async test that is never started, should have status Not Run", {timeout:1000});
|
||||
|
||||
|
||||
test(function(t) {
|
||||
window.global = 1;
|
||||
t.add_cleanup(function() {delete window.global});
|
||||
assert_equals(window.global, 1);
|
||||
},
|
||||
"Test that defines a global and cleans it up");
|
||||
|
||||
test(function() {assert_equals(window.global, undefined)},
|
||||
"Test that cleanup handlers from previous test ran");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
119
tests/wpt/web-platform-tests/resources/apisample10.html
Normal file
119
tests/wpt/web-platform-tests/resources/apisample10.html
Normal file
|
@ -0,0 +1,119 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Async Tests and Promises</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Async Tests and Promises</h1>
|
||||
<p>This test assumes ECMAScript 6 Promise support. Some failures are expected.</p>
|
||||
<div id="log"></div>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
<script>
|
||||
|
||||
test(function() {
|
||||
var p = new Promise(function(resolve, reject) {});
|
||||
assert_true('then' in p);
|
||||
assert_equals(typeof Promise.resolve, 'function');
|
||||
assert_equals(typeof Promise.reject, 'function');
|
||||
}, "Promises are supported in your browser");
|
||||
|
||||
(function() {
|
||||
var t = async_test("Promise resolution");
|
||||
t.step(function() {
|
||||
Promise.resolve('x').then(
|
||||
t.step_func(function(value) {
|
||||
assert_equals(value, 'x');
|
||||
t.done();
|
||||
}),
|
||||
t.unreached_func('Promise should not reject')
|
||||
);
|
||||
});
|
||||
}());
|
||||
|
||||
(function() {
|
||||
var t = async_test("Promise rejection");
|
||||
t.step(function() {
|
||||
Promise.reject(Error('fail')).then(
|
||||
t.unreached_func('Promise should reject'),
|
||||
t.step_func(function(reason) {
|
||||
assert_true(reason instanceof Error);
|
||||
assert_equals(reason.message, 'fail');
|
||||
t.done();
|
||||
})
|
||||
);
|
||||
});
|
||||
}());
|
||||
|
||||
(function() {
|
||||
var t = async_test("Promises resolution chaining");
|
||||
t.step(function() {
|
||||
var resolutions = [];
|
||||
Promise.resolve('a').then(
|
||||
t.step_func(function(value) {
|
||||
resolutions.push(value);
|
||||
return 'b';
|
||||
})
|
||||
).then(
|
||||
t.step_func(function(value) {
|
||||
resolutions.push(value);
|
||||
return 'c';
|
||||
})
|
||||
).then(
|
||||
t.step_func(function(value) {
|
||||
resolutions.push(value);
|
||||
|
||||
assert_array_equals(resolutions, ['a', 'b', 'c']);
|
||||
t.done();
|
||||
})
|
||||
).catch(
|
||||
t.unreached_func('promise should not have rejected')
|
||||
);
|
||||
});
|
||||
}());
|
||||
|
||||
(function() {
|
||||
var t = async_test("Use of step_func with Promises");
|
||||
t.step(function() {
|
||||
var resolutions = [];
|
||||
Promise.resolve('x').then(
|
||||
t.step_func_done(),
|
||||
t.unreached_func('Promise should not have rejected')
|
||||
);
|
||||
});
|
||||
}());
|
||||
|
||||
(function() {
|
||||
var t = async_test("Promises and test assertion failures (should fail)");
|
||||
t.step(function() {
|
||||
var resolutions = [];
|
||||
Promise.resolve('x').then(
|
||||
t.step_func(function(value) {
|
||||
assert_true(false, 'This failure is expected');
|
||||
})
|
||||
).then(
|
||||
t.unreached_func('Promise should not have resolved')
|
||||
).catch(
|
||||
t.unreached_func('Promise should not have rejected')
|
||||
);
|
||||
});
|
||||
}());
|
||||
|
||||
(function() {
|
||||
var t = async_test("Use of unreached_func with Promises (should fail)");
|
||||
t.step(function() {
|
||||
var resolutions = [];
|
||||
var r;
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
// Reject instead of resolve, to demonstrate failure.
|
||||
reject(123);
|
||||
});
|
||||
p.then(
|
||||
function(value) {
|
||||
assert_equals(value, 123, 'This should not actually happen');
|
||||
},
|
||||
t.unreached_func('This failure is expected')
|
||||
);
|
||||
});
|
||||
}());
|
||||
</script>
|
99
tests/wpt/web-platform-tests/resources/apisample11.html
Normal file
99
tests/wpt/web-platform-tests/resources/apisample11.html
Normal file
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Example with iframe that notifies containing document via callbacks</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
</head>
|
||||
<body onload="start_test_in_iframe()">
|
||||
<h1>Callbacks From Tests Running In An IFRAME</h1>
|
||||
<p>A test is run inside an <tt>iframe</tt> with a same origin document. The
|
||||
containing document should receive callbacks as the tests progress inside the
|
||||
<tt>iframe</tt>. A single passing test is expected in the summary below.
|
||||
<div id="log"></div>
|
||||
|
||||
<script>
|
||||
var callbacks = [];
|
||||
var START = 1
|
||||
var TEST_STATE = 2
|
||||
var RESULT = 3
|
||||
var COMPLETION = 4
|
||||
var test_complete = false;
|
||||
|
||||
setup({explicit_done: true});
|
||||
|
||||
// The following callbacks are called for tests in this document as well as the
|
||||
// tests in the IFRAME. Currently, callbacks invoked from this document and any
|
||||
// child document are indistinguishable from each other.
|
||||
|
||||
function start_callback(properties) {
|
||||
callbacks.push(START);
|
||||
}
|
||||
|
||||
function test_state_callback(test) {
|
||||
callbacks.push(TEST_STATE);
|
||||
}
|
||||
|
||||
function result_callback(test) {
|
||||
callbacks.push(RESULT);
|
||||
}
|
||||
|
||||
function completion_callback(tests, status) {
|
||||
if (test_complete) {
|
||||
return;
|
||||
}
|
||||
test_complete = true;
|
||||
callbacks.push(COMPLETION);
|
||||
verify_received_callbacks();
|
||||
done();
|
||||
}
|
||||
|
||||
function verify_received_callbacks() {
|
||||
var copy_of_callbacks = callbacks.slice(0);
|
||||
|
||||
// Note that you can't run test assertions directly in a callback even if
|
||||
// this is a file test. When the callback is invoked from a same-origin child
|
||||
// page, the callstack reaches into the calling child document. Any
|
||||
// exception thrown in a callback will be handled by the child rather than
|
||||
// this document.
|
||||
test(
|
||||
function() {
|
||||
// callbacks list should look like:
|
||||
// START 1*(TEST_STATE) RESULT COMPLETION
|
||||
assert_equals(copy_of_callbacks.shift(), START,
|
||||
"The first received callback should be 'start_callback'.");
|
||||
assert_equals(copy_of_callbacks.shift(), TEST_STATE,
|
||||
"'test_state_callback' should be received before any " +
|
||||
"result or completion callbacks.");
|
||||
while(copy_of_callbacks.length > 0) {
|
||||
var callback = copy_of_callbacks.shift();
|
||||
if (callback != TEST_STATE) {
|
||||
copy_of_callbacks.unshift(callback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert_equals(copy_of_callbacks.shift(), RESULT,
|
||||
"'test_state_callback' should be followed by 'result_callback'.");
|
||||
assert_equals(copy_of_callbacks.shift(), COMPLETION,
|
||||
"Final 'result_callback' should be followed by 'completion_callback'.");
|
||||
assert_equals(copy_of_callbacks.length, 0,
|
||||
"'completion_callback' should be the last callback.");
|
||||
});
|
||||
}
|
||||
|
||||
function start_test_in_iframe() {
|
||||
// This document is going to clear any received callbacks and maintain
|
||||
// radio silence until the test in the iframe runs to completion. The
|
||||
// completion_callback() will then complete the testing on this document.
|
||||
callbacks.length = 0;
|
||||
var iframe = document.createElement("iframe");
|
||||
// apisample6.html has a single test.
|
||||
iframe.src = "apisample6.html";
|
||||
iframe.style.setProperty("display", "none");
|
||||
document.getElementById("target").appendChild(iframe);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="target">
|
||||
</div>
|
||||
</body>
|
67
tests/wpt/web-platform-tests/resources/apisample12.html
Normal file
67
tests/wpt/web-platform-tests/resources/apisample12.html
Normal file
|
@ -0,0 +1,67 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Example with iframe that notifies containing document via cross document messaging</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Notifications From Tests Running In An IFRAME</h1>
|
||||
<p>A test is run inside an <tt>iframe</tt> with a same origin document. The
|
||||
containing document should receive messages via <tt>postMessage</tt>/
|
||||
<tt>onmessage</tt> as the tests progress inside the <tt>iframe</tt>. A single
|
||||
passing test is expected in the summary below.
|
||||
</p>
|
||||
<div id="log"></div>
|
||||
|
||||
<script>
|
||||
var t = async_test("Containing document receives messages");
|
||||
var start_received = false;
|
||||
var result_received = false;
|
||||
var completion_received = false;
|
||||
|
||||
// These are the messages that are expected to be seen while running the tests
|
||||
// in the IFRAME.
|
||||
var expected_messages = [
|
||||
t.step_func(
|
||||
function(message) {
|
||||
assert_equals(message.data.type, "start");
|
||||
assert_own_property(message.data, "properties");
|
||||
}),
|
||||
|
||||
t.step_func(
|
||||
function(message) {
|
||||
assert_equals(message.data.type, "test_state");
|
||||
assert_equals(message.data.test.status, message.data.test.NOTRUN);
|
||||
}),
|
||||
|
||||
t.step_func(
|
||||
function(message) {
|
||||
assert_equals(message.data.type, "result");
|
||||
assert_equals(message.data.test.status, message.data.test.PASS);
|
||||
}),
|
||||
|
||||
t.step_func(
|
||||
function(message) {
|
||||
assert_equals(message.data.type, "complete");
|
||||
assert_equals(message.data.tests.length, 1);
|
||||
assert_equals(message.data.tests[0].status,
|
||||
message.data.tests[0].PASS);
|
||||
assert_equals(message.data.status.status, message.data.status.OK);
|
||||
t.done();
|
||||
}),
|
||||
|
||||
t.unreached_func("Too many messages received")
|
||||
];
|
||||
|
||||
on_event(window,
|
||||
"message",
|
||||
function(message) {
|
||||
var handler = expected_messages.shift();
|
||||
handler(message);
|
||||
});
|
||||
</script>
|
||||
<iframe src="apisample6.html" style="display:none">
|
||||
<!-- apisample6 implements a file_is_test test. -->
|
||||
</iframe>
|
||||
</body>
|
132
tests/wpt/web-platform-tests/resources/apisample13.html
Normal file
132
tests/wpt/web-platform-tests/resources/apisample13.html
Normal file
|
@ -0,0 +1,132 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Promise Tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Promise Tests</h1>
|
||||
<p>This test demonstrates the use of <tt>promise_test</tt>. Assumes ECMAScript 6
|
||||
Promise support. Some failures are expected.</p>
|
||||
<div id="log"></div>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
<script>
|
||||
test(
|
||||
function() {
|
||||
var p = new Promise(function(resolve, reject){});
|
||||
assert_true("then" in p);
|
||||
assert_equals(typeof Promise.resolve, "function");
|
||||
assert_equals(typeof Promise.reject, "function");
|
||||
},
|
||||
"Promises are supported in your browser");
|
||||
|
||||
promise_test(
|
||||
function() {
|
||||
return Promise.resolve("x")
|
||||
.then(
|
||||
function(value) {
|
||||
assert_equals(value,
|
||||
"x",
|
||||
"Fulfilled promise should pass result to " +
|
||||
"fulfill reaction.");
|
||||
});
|
||||
},
|
||||
"Promise fulfillment with result");
|
||||
|
||||
promise_test(
|
||||
function(t) {
|
||||
return Promise.reject(new Error("fail"))
|
||||
.then(t.unreached_func("Promise should reject"),
|
||||
function(reason) {
|
||||
assert_true(
|
||||
reason instanceof Error,
|
||||
"Rejected promise should pass reason to fulfill reaction.");
|
||||
assert_equals(
|
||||
reason.message,
|
||||
"fail",
|
||||
"Rejected promise should pass reason to reject reaction.");
|
||||
});
|
||||
},
|
||||
"Promise rejection with result");
|
||||
|
||||
promise_test(
|
||||
function() {
|
||||
var resolutions = [];
|
||||
return Promise.resolve("a")
|
||||
.then(
|
||||
function(value) {
|
||||
resolutions.push(value);
|
||||
return "b";
|
||||
})
|
||||
.then(
|
||||
function(value) {
|
||||
resolutions.push(value);
|
||||
return "c";
|
||||
})
|
||||
.then(
|
||||
function(value) {
|
||||
resolutions.push(value);
|
||||
assert_array_equals(resolutions, ["a", "b", "c"]);
|
||||
});
|
||||
},
|
||||
"Chain of promise resolutions");
|
||||
|
||||
promise_test(
|
||||
function(t) {
|
||||
var resolutions = [];
|
||||
return Promise.resolve("x")
|
||||
.then(
|
||||
function(value) {
|
||||
assert_true(false, "Expected failure.");
|
||||
})
|
||||
.then(t.unreached_func("UNEXPECTED FAILURE: Promise should not have resolved."));
|
||||
},
|
||||
"Assertion failure in a fulfill reaction (should FAIL with an expected failure)");
|
||||
|
||||
promise_test(
|
||||
function(t) {
|
||||
return new Promise(
|
||||
function(resolve, reject) {
|
||||
reject(123);
|
||||
})
|
||||
.then(t.unreached_func("UNEXPECTED FAILURE: Fulfill reaction reached after rejection."),
|
||||
t.unreached_func("Expected failure."));
|
||||
},
|
||||
"unreached_func as reactor (should FAIL with an expected failure)");
|
||||
|
||||
promise_test(
|
||||
function() {
|
||||
return true;
|
||||
},
|
||||
"promise_test with function that doesn't return a Promise");
|
||||
|
||||
promise_test(function(){},
|
||||
"promise_test with function that doesn't return anything");
|
||||
|
||||
promise_test(
|
||||
function() {
|
||||
return Promise.reject("Expected rejection");
|
||||
},
|
||||
"promise_test with unhandled rejection (should FAIL)");
|
||||
|
||||
promise_test(
|
||||
function() {
|
||||
return Promise.resolve(10)
|
||||
.then(
|
||||
function(value) {
|
||||
throw Error("Expected exception.");
|
||||
});
|
||||
},
|
||||
"promise_test with unhandled exception in fulfill reaction (should FAIL)");
|
||||
|
||||
promise_test(
|
||||
function(t) {
|
||||
return Promise.reject(10)
|
||||
.then(
|
||||
t.unreached_func("UNEXPECTED FAILURE: Fulfill reaction reached after rejection."),
|
||||
function(value) {
|
||||
throw Error("Expected exception.");
|
||||
});
|
||||
},
|
||||
"promise_test with unhandled exception in reject reaction (should FAIL)");
|
||||
</script>
|
29
tests/wpt/web-platform-tests/resources/apisample14.html
Normal file
29
tests/wpt/web-platform-tests/resources/apisample14.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dedicated Worker Tests</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Dedicated Web Worker Tests</h1>
|
||||
<p>Demonstrates running <tt>testharness</tt> based tests inside a dedicated web worker.
|
||||
<p>The test harness is expected to fail due to an uncaught exception in one worker.</p>
|
||||
<div id="log"></div>
|
||||
|
||||
<script>
|
||||
test(function(t) {
|
||||
assert_true("Worker" in self, "Browser should support Workers");
|
||||
},
|
||||
"Browser supports Workers");
|
||||
|
||||
fetch_tests_from_worker(new Worker("apisample-worker.js"));
|
||||
|
||||
fetch_tests_from_worker(new Worker("apisample-error-worker.js"));
|
||||
|
||||
test(function(t) {
|
||||
assert_false(false, "False is false");
|
||||
},
|
||||
"Test running on main document.");
|
||||
</script>
|
||||
</body>
|
26
tests/wpt/web-platform-tests/resources/apisample15.html
Normal file
26
tests/wpt/web-platform-tests/resources/apisample15.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Example with a shared worker</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Shared Web Worker Tests</h1>
|
||||
<p>Demonstrates running <tt>testharness</tt> based tests inside a shared worker.
|
||||
<p>The test harness should time out due to one of the tests in the worker timing out.
|
||||
<p>This test assumes that the browser supports <a href="http://www.w3.org/TR/workers/#shared-workers-and-the-sharedworker-interface">shared web workers</a>.
|
||||
<div id="log"></div>
|
||||
|
||||
<script>
|
||||
test(
|
||||
function(t) {
|
||||
assert_true("SharedWorker" in self,
|
||||
"Browser should support SharedWorkers");
|
||||
},
|
||||
"Browser supports SharedWorkers");
|
||||
|
||||
fetch_tests_from_worker(new SharedWorker("apisample-worker.js",
|
||||
"My shared worker"));
|
||||
</script>
|
||||
</body>
|
62
tests/wpt/web-platform-tests/resources/apisample16.html
Normal file
62
tests/wpt/web-platform-tests/resources/apisample16.html
Normal file
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Example with a service worker</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Service Worker Tests</h1>
|
||||
<p>Demonstrates running <tt>testharness</tt> based tests inside a service worker.
|
||||
<p>The test harness should time out due to one of the tests inside the worker timing out.
|
||||
<p>This test assumes that the browser supports <a href="http://www.w3.org/TR/service-workers/">ServiceWorkers</a>.
|
||||
<div id="log"></div>
|
||||
|
||||
<script>
|
||||
test(
|
||||
function(t) {
|
||||
assert_true("serviceWorker" in navigator,
|
||||
"navigator.serviceWorker exists");
|
||||
},
|
||||
"Browser supports ServiceWorker");
|
||||
|
||||
promise_test(
|
||||
function() {
|
||||
// Since the service worker registration could be in an indeterminate
|
||||
// state (due to, for example, a previous test run failing), we start by
|
||||
// unregstering our service worker and then registering it again.
|
||||
var scope = "/service-worker-scope";
|
||||
var worker_url = "apisample-worker.js";
|
||||
|
||||
return navigator.serviceWorker.register(worker_url, {scope: scope})
|
||||
.then(
|
||||
function(registration) {
|
||||
return registration.unregister();
|
||||
})
|
||||
.then(
|
||||
function() {
|
||||
return navigator.serviceWorker.register(worker_url, {scope: scope});
|
||||
})
|
||||
.then(
|
||||
function(registration) {
|
||||
add_completion_callback(
|
||||
function() {
|
||||
registration.unregister();
|
||||
});
|
||||
|
||||
return new Promise(
|
||||
function(resolve) {
|
||||
registration.addEventListener("updatefound",
|
||||
function() {
|
||||
resolve(registration.installing);
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(
|
||||
function(worker) {
|
||||
fetch_tests_from_worker(worker);
|
||||
});
|
||||
},
|
||||
"Register ServiceWorker");
|
||||
</script>
|
||||
</body>
|
19
tests/wpt/web-platform-tests/resources/apisample2.htm
Normal file
19
tests/wpt/web-platform-tests/resources/apisample2.htm
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Sample HTML5 API Tests</title>
|
||||
</head>
|
||||
<body onload="load_test_attr.done()">
|
||||
<h1>Sample HTML5 API Tests</h1>
|
||||
<p>There should be two results</p>
|
||||
<div id="log"></div>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
<script>
|
||||
setup({explicit_done:true})
|
||||
test(function() {assert_true(true)}, "Test defined before onload");
|
||||
|
||||
onload = function() {test(function (){assert_true(true)}, "Test defined after onload");
|
||||
done();
|
||||
}
|
||||
</script>
|
17
tests/wpt/web-platform-tests/resources/apisample3.htm
Normal file
17
tests/wpt/web-platform-tests/resources/apisample3.htm
Normal file
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Sample HTML5 API Tests</title>
|
||||
</head>
|
||||
<script src="testharness.js"></script>
|
||||
|
||||
<body onload="load_test_attr.done()">
|
||||
<h1>Sample HTML5 API Tests</h1>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
setup({explicit_timeout:true});
|
||||
var t = async_test("This test should give a status of 'Not Run' without a delay");
|
||||
timeout();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
16
tests/wpt/web-platform-tests/resources/apisample4.htm
Normal file
16
tests/wpt/web-platform-tests/resources/apisample4.htm
Normal file
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Harness Handling Uncaught Exception</title>
|
||||
</head>
|
||||
<script src="testharness.js"></script>
|
||||
|
||||
<body>
|
||||
<h1>Harness Handling Uncaught Exception</h1>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
var t = async_test("This should show a harness status of 'Error' and a test status of 'Not Run'");
|
||||
throw new Error("Example Error");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
18
tests/wpt/web-platform-tests/resources/apisample5.htm
Normal file
18
tests/wpt/web-platform-tests/resources/apisample5.htm
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Harness Ignoring Uncaught Exception</title>
|
||||
</head>
|
||||
<script src="testharness.js"></script>
|
||||
|
||||
<body>
|
||||
<h1>Harness Ignoring Uncaught Exception</h1>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
setup({allow_uncaught_exception:true});
|
||||
var t = async_test("setup({allow_uncaught_exception:true}) should allow tests to pass even if there is an exception");
|
||||
onerror = t.step_func(function() {t.done()});
|
||||
throw new Error("Example Error");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
10
tests/wpt/web-platform-tests/resources/apisample6.html
Normal file
10
tests/wpt/web-platform-tests/resources/apisample6.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE HTML>
|
||||
<title>Example with file_is_test</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
<script>
|
||||
onload = function() {
|
||||
assert_true(true);
|
||||
done();
|
||||
}
|
||||
</script>
|
10
tests/wpt/web-platform-tests/resources/apisample7.html
Normal file
10
tests/wpt/web-platform-tests/resources/apisample7.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE HTML>
|
||||
<title>Example with file_is_test (should fail)</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
<script>
|
||||
onload = function() {
|
||||
assert_true(false);
|
||||
done();
|
||||
}
|
||||
</script>
|
8
tests/wpt/web-platform-tests/resources/apisample8.html
Normal file
8
tests/wpt/web-platform-tests/resources/apisample8.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<title>Example single page test with no body</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
<script>
|
||||
assert_true(true);
|
||||
done();
|
||||
</script>
|
7
tests/wpt/web-platform-tests/resources/apisample9.html
Normal file
7
tests/wpt/web-platform-tests/resources/apisample9.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
<title>Example single page test with no asserts</title>
|
||||
<script src="testharness.js"></script>
|
||||
<script src="testharnessreport.js"></script>
|
||||
<script>
|
||||
done();
|
||||
</script>
|
548
tests/wpt/web-platform-tests/resources/docs/api.md
Normal file
548
tests/wpt/web-platform-tests/resources/docs/api.md
Normal file
|
@ -0,0 +1,548 @@
|
|||
## Introduction ##
|
||||
|
||||
testharness.js provides a framework for writing testcases. It is intended to
|
||||
provide a convenient API for making common assertions, and to work both
|
||||
for testing synchronous and asynchronous DOM features in a way that
|
||||
promotes clear, robust, tests.
|
||||
|
||||
## Basic Usage ##
|
||||
|
||||
The test harness script can be used from HTML or SVG documents and web worker
|
||||
scripts.
|
||||
|
||||
From an HTML or SVG document, start by importing both `testharness.js` and
|
||||
`testharnessreport.js` scripts into the document:
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
Refer to the [Web Workers](#web-workers) section for details and an example on
|
||||
testing within a web worker.
|
||||
|
||||
Within each file one may define one or more tests. Each test is atomic in the
|
||||
sense that a single test has a single result (`PASS`/`FAIL`/`TIMEOUT`/`NOTRUN`).
|
||||
Within each test one may have a number of asserts. The test fails at the first
|
||||
failing assert, and the remainder of the test is (typically) not run.
|
||||
|
||||
If the file containing the tests is a HTML file, a table containing the test
|
||||
results will be added to the document after all tests have run. By default this
|
||||
will be added to a `div` element with `id=log` if it exists, or a new `div`
|
||||
element appended to `document.body` if it does not.
|
||||
|
||||
NOTE: By default tests must be created before the load event fires. For ways
|
||||
to create tests after the load event, see "Determining when all tests
|
||||
are complete", below.
|
||||
|
||||
## Synchronous Tests ##
|
||||
|
||||
To create a synchronous test use the test() function:
|
||||
|
||||
test(test_function, name, properties)
|
||||
|
||||
`test_function` is a function that contains the code to test. For example a
|
||||
trivial passing test would be:
|
||||
|
||||
test(function() {assert_true(true)}, "assert_true with true")
|
||||
|
||||
The function passed in is run in the `test()` call.
|
||||
|
||||
`properties` is a javascript object for passing extra options to the
|
||||
test. Currently it is only used to provide test-specific
|
||||
metadata, as described in the [metadata](#metadata) section below.
|
||||
|
||||
## Asynchronous Tests ##
|
||||
|
||||
Testing asynchronous features is somewhat more complex since the result of
|
||||
a test may depend on one or more events or other callbacks. The API provided
|
||||
for testing these features is indended to be rather low-level but hopefully
|
||||
applicable to many situations.
|
||||
|
||||
To create a test, one starts by getting a Test object using async_test:
|
||||
|
||||
async_test(name, properties)
|
||||
|
||||
e.g.
|
||||
var t = async_test("Simple async test")
|
||||
|
||||
Assertions can be added to the test by calling the step method of the test
|
||||
object with a function containing the test assertions:
|
||||
|
||||
t.step(function() {assert_true(true)});
|
||||
|
||||
When all the steps are complete, the done() method must be called:
|
||||
|
||||
t.done();
|
||||
|
||||
As a convenience, async_test can also takes a function as first argument.
|
||||
This function is called with the test object as both its `this` object and
|
||||
first argument. The above example can be rewritten as:
|
||||
|
||||
async_test(function(t) {
|
||||
object.some_event = function() {
|
||||
t.step(function (){assert_true(true); t.done();});
|
||||
};
|
||||
}, "Simple async test");
|
||||
|
||||
which avoids cluttering the global scope with references to async
|
||||
tests instances.
|
||||
|
||||
The properties argument is identical to that for `test()`.
|
||||
|
||||
In many cases it is convenient to run a step in response to an event or a
|
||||
callback. A convenient method of doing this is through the step_func method
|
||||
which returns a function that, when called runs a test step. For example
|
||||
|
||||
object.some_event = t.step_func(function(e) {assert_true(e.a)});
|
||||
|
||||
For asynchronous callbacks that should never execute, `unreached_func` can
|
||||
be used. For example:
|
||||
|
||||
object.some_event = t.unreached_func("some_event should not fire");
|
||||
|
||||
## Promise Tests ##
|
||||
|
||||
`promise_test` can be used to test APIs that are based on Promises:
|
||||
|
||||
promise_test(test_function, name, properties)
|
||||
|
||||
`test_function` is a function that receives a test as an argument and returns a
|
||||
promise. The test completes when the returned promise resolves. The test fails
|
||||
if the returned promise rejects.
|
||||
|
||||
E.g.:
|
||||
|
||||
function foo() {
|
||||
return Promise.resolve("foo");
|
||||
}
|
||||
|
||||
promise_test(function() {
|
||||
return foo()
|
||||
.then(function(result) {
|
||||
assert_equals(result, "foo", "foo should return 'foo'");
|
||||
});
|
||||
}, "Simple example");
|
||||
|
||||
In the example above, `foo()` returns a Promise that resolves with the string
|
||||
"foo". The `test_function` passed into `promise_test` invokes `foo` and attaches
|
||||
a resolve reaction that verifies the returned value.
|
||||
|
||||
Note that in the promise chain constructed in `test_function` assertions don't
|
||||
need to wrapped in `step` or `step_func` calls.
|
||||
|
||||
`promise_rejects` can be used to test Promises that need to reject:
|
||||
|
||||
promise_rejects(test_object, code, promise)
|
||||
|
||||
The `code` argument is equivalent to the same argument to the `assert_throws`
|
||||
function.
|
||||
|
||||
Here's an example where the `bar()` function returns a Promise that rejects
|
||||
with a TypeError:
|
||||
|
||||
function bar() {
|
||||
return Promise.reject(new TypeError());
|
||||
}
|
||||
|
||||
promise_test(function(t) {
|
||||
return promise_rejects(t, new TypeError(), bar);
|
||||
}, "Another example");
|
||||
|
||||
## Single Page Tests ##
|
||||
|
||||
Sometimes, particularly when dealing with asynchronous behaviour,
|
||||
having exactly one test per page is desirable, and the overhead of
|
||||
wrapping everything in functions for isolation becomes
|
||||
burdensome. For these cases `testharness.js` support "single page
|
||||
tests".
|
||||
|
||||
In order for a test to be interpreted as a single page test, the
|
||||
it must simply not call `test()` or `async_test()` anywhere on the page, and
|
||||
must call the `done()` function to indicate that the test is complete. All
|
||||
the `assert_*` functions are avaliable as normal, but are called without
|
||||
the normal step function wrapper. For example:
|
||||
|
||||
<!doctype html>
|
||||
<title>Example single-page test</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
assert_equals(document.body, document.getElementsByTagName("body")[0])
|
||||
done()
|
||||
</script>
|
||||
|
||||
The test title for sinple page tests is always taken from `document.title`.
|
||||
|
||||
## Making assertions ##
|
||||
|
||||
Functions for making assertions start `assert_`. The full list of
|
||||
asserts avaliable is documented in the [asserts](#asserts) section
|
||||
below.. The general signature is
|
||||
|
||||
assert_something(actual, expected, description)
|
||||
|
||||
although not all assertions precisely match this pattern e.g. `assert_true`
|
||||
only takes `actual` and `description` as arguments.
|
||||
|
||||
The description parameter is used to present more useful error messages when
|
||||
a test fails
|
||||
|
||||
NOTE: All asserts must be located in a `test()` or a step of an
|
||||
`async_test()`, unless the test is a single page test. Asserts outside
|
||||
these places won't be detected correctly by the harness and may cause
|
||||
unexpected exceptions that will lead to an error in the harness.
|
||||
|
||||
## Cleanup ##
|
||||
|
||||
Occasionally tests may create state that will persist beyond the test itself.
|
||||
In order to ensure that tests are independent, such state should be cleaned
|
||||
up once the test has a result. This can be achieved by adding cleanup
|
||||
callbacks to the test. Such callbacks are registered using the `add_cleanup`
|
||||
function on the test object. All registered callbacks will be run as soon as
|
||||
the test result is known. For example
|
||||
|
||||
test(function() {
|
||||
window.some_global = "example";
|
||||
this.add_cleanup(function() {delete window.some_global});
|
||||
assert_true(false);
|
||||
});
|
||||
|
||||
## Harness Timeout ##
|
||||
|
||||
The overall harness admits two timeout values `"normal"` (the
|
||||
default) and `"long"`, used for tests which have an unusually long
|
||||
runtime. After the timeout is reached, the harness will stop
|
||||
waiting for further async tests to complete. By default the
|
||||
timeouts are set to 10s and 60s, respectively, but may be changed
|
||||
when the test is run on hardware with different performance
|
||||
characteristics to a common desktop computer. In order to opt-in
|
||||
to the longer test timeout, the test must specify a meta element:
|
||||
|
||||
<meta name="timeout" content="long">
|
||||
|
||||
Occasionally tests may have a race between the harness timing out and
|
||||
a particular test failing; typically when the test waits for some event
|
||||
that never occurs. In this case it is possible to use `test.force_timeout()`
|
||||
in place of `assert_unreached()`, to immediately fail the test but with a
|
||||
status of `TIMEOUT`. This should only be used as a last resort when it is
|
||||
not possible to make the test reliable in some other way.
|
||||
|
||||
## Setup ##
|
||||
|
||||
Sometimes tests require non-trivial setup that may fail. For this purpose
|
||||
there is a `setup()` function, that may be called with one or two arguments.
|
||||
The two argument version is:
|
||||
|
||||
setup(func, properties)
|
||||
|
||||
The one argument versions may omit either argument.
|
||||
func is a function to be run synchronously. `setup()` becomes a no-op once
|
||||
any tests have returned results. Properties are global properties of the test
|
||||
harness. Currently recognised properties are:
|
||||
|
||||
`explicit_done` - Wait for an explicit call to done() before declaring all
|
||||
tests complete (see below; implicitly true for single page tests)
|
||||
|
||||
`output_document` - The document to which results should be logged. By default
|
||||
this is the current document but could be an ancestor document in some cases
|
||||
e.g. a SVG test loaded in an HTML wrapper
|
||||
|
||||
`explicit_timeout` - disable file timeout; only stop waiting for results
|
||||
when the `timeout()` function is called (typically for use when integrating
|
||||
with some existing test framework that has its own timeout mechanism).
|
||||
|
||||
`allow_uncaught_exception` - don't treat an uncaught exception as an error;
|
||||
needed when e.g. testing the `window.onerror` handler.
|
||||
|
||||
`timeout_multiplier` - Multiplier to apply to per-test timeouts.
|
||||
|
||||
## Determining when all tests are complete ##
|
||||
|
||||
By default the test harness will assume there are no more results to come
|
||||
when:
|
||||
|
||||
1. There are no `Test` objects that have been created but not completed
|
||||
2. The load event on the document has fired
|
||||
|
||||
This behaviour can be overridden by setting the `explicit_done` property to
|
||||
true in a call to `setup()`. If `explicit_done` is true, the test harness will
|
||||
not assume it is done until the global `done()` function is called. Once `done()`
|
||||
is called, the two conditions above apply like normal.
|
||||
|
||||
Dedicated and shared workers don't have an event that corresponds to the `load`
|
||||
event in a document. Therefore these worker tests always behave as if the
|
||||
`explicit_done` property is set to true. Service workers depend on the
|
||||
[install](https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-global-scope-install-event)
|
||||
event which is fired following the completion of [running the
|
||||
worker](https://html.spec.whatwg.org/multipage/workers.html#run-a-worker).
|
||||
|
||||
## Generating tests ##
|
||||
|
||||
There are scenarios in which is is desirable to create a large number of
|
||||
(synchronous) tests that are internally similar but vary in the parameters
|
||||
used. To make this easier, the `generate_tests` function allows a single
|
||||
function to be called with each set of parameters in a list:
|
||||
|
||||
generate_tests(test_function, parameter_lists, properties)
|
||||
|
||||
For example:
|
||||
|
||||
generate_tests(assert_equals, [
|
||||
["Sum one and one", 1+1, 2],
|
||||
["Sum one and zero", 1+0, 1]
|
||||
])
|
||||
|
||||
Is equivalent to:
|
||||
|
||||
test(function() {assert_equals(1+1, 2)}, "Sum one and one")
|
||||
test(function() {assert_equals(1+0, 1)}, "Sum one and zero")
|
||||
|
||||
Note that the first item in each parameter list corresponds to the name of
|
||||
the test.
|
||||
|
||||
The properties argument is identical to that for `test()`. This may be a
|
||||
single object (used for all generated tests) or an array.
|
||||
|
||||
## Callback API ##
|
||||
|
||||
The framework provides callbacks corresponding to 4 events:
|
||||
|
||||
* `start` - triggered when the first Test is created
|
||||
* `test_state` - triggered when a test state changes
|
||||
* `result` - triggered when a test result is recieved
|
||||
* `complete` - triggered when all results are recieved
|
||||
|
||||
The page defining the tests may add callbacks for these events by calling
|
||||
the following methods:
|
||||
|
||||
`add_start_callback(callback)` - callback called with no arguments
|
||||
|
||||
`add_test_state_callback(callback)` - callback called with a test argument
|
||||
|
||||
`add_result_callback(callback)` - callback called with a test argument
|
||||
|
||||
`add_completion_callback(callback)` - callback called with an array of tests
|
||||
and an status object
|
||||
|
||||
tests have the following properties:
|
||||
|
||||
* `status` - A status code. This can be compared to the `PASS`, `FAIL`,
|
||||
`TIMEOUT` and `NOTRUN` properties on the test object
|
||||
|
||||
* `message` - A message indicating the reason for failure. In the future this
|
||||
will always be a string
|
||||
|
||||
The status object gives the overall status of the harness. It has the
|
||||
following properties:
|
||||
|
||||
* `status` - Can be compared to the `OK`, `ERROR` and `TIMEOUT` properties
|
||||
|
||||
* `message` - An error message set when the status is `ERROR`
|
||||
|
||||
## External API ##
|
||||
|
||||
In order to collect the results of multiple pages containing tests, the test
|
||||
harness will, when loaded in a nested browsing context, attempt to call
|
||||
certain functions in each ancestor and opener browsing context:
|
||||
|
||||
* start - `start_callback`
|
||||
* test\_state - `test_state_callback`
|
||||
* result - `result_callback`
|
||||
* complete - `completion_callback`
|
||||
|
||||
These are given the same arguments as the corresponding internal callbacks
|
||||
described above.
|
||||
|
||||
## External API through cross-document messaging ##
|
||||
|
||||
Where supported, the test harness will also send messages using cross-document
|
||||
messaging to each ancestor and opener browsing context. Since it uses the
|
||||
wildcard keyword (\*), cross-origin communication is enabled and script on
|
||||
different origins can collect the results.
|
||||
|
||||
This API follows similar conventions as those described above only slightly
|
||||
modified to accommodate message event API. Each message is sent by the harness
|
||||
is passed a single vanilla object, available as the `data` property of the event
|
||||
object. These objects are structures as follows:
|
||||
|
||||
* start - `{ type: "start" }`
|
||||
* test\_state - `{ type: "test_state", test: Test }`
|
||||
* result - `{ type: "result", test: Test }`
|
||||
* complete - `{ type: "complete", tests: [Test, ...], status: TestsStatus }`
|
||||
|
||||
## Web Workers ##
|
||||
|
||||
The `testharness.js` script can be used from within [dedicated workers, shared
|
||||
workers](https://html.spec.whatwg.org/multipage/workers.html) and [service
|
||||
workers](https://slightlyoff.github.io/ServiceWorker/spec/service_worker/).
|
||||
|
||||
Testing from a worker script is different from testing from an HTML document in
|
||||
several ways:
|
||||
|
||||
* Workers have no reporting capability since they are runing in the background.
|
||||
Hence they rely on `testharness.js` running in a companion client HTML document
|
||||
for reporting.
|
||||
|
||||
* Shared and service workers do not have a unique client document since there
|
||||
could be more than one document that communicates with these workers. So a
|
||||
client document needs to explicitly connect to a worker and fetch test results
|
||||
from it using `fetch_tests_from_worker`. This is true even for a dedicated
|
||||
worker. Once connected, the individual tests running in the worker (or those
|
||||
that have already run to completion) will be automatically reflected in the
|
||||
client document.
|
||||
|
||||
* The client document controls the timeout of the tests. All worker scripts act
|
||||
as if they were started with the `explicit_timeout` option (see the [Harness
|
||||
timeout](#harness-timeout) section).
|
||||
|
||||
* Dedicated and shared workers don't have an equivalent of an `onload` event.
|
||||
Thus the test harness has no way to know when all tests have completed (see
|
||||
[Determining when all tests are
|
||||
complete](#determining-when-all-tests-are-complete)). So these worker tests
|
||||
behave as if they were started with the `explicit_done` option. Service
|
||||
workers depend on the
|
||||
[oninstall](https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-global-scope-install-event)
|
||||
event and don't require an explicit `done` call.
|
||||
|
||||
Here's an example that uses a dedicated worker.
|
||||
|
||||
`worker.js`:
|
||||
|
||||
importScripts("/resources/testharness.js");
|
||||
|
||||
test(function(t) {
|
||||
assert_true(true, "true is true");
|
||||
}, "Simple test");
|
||||
|
||||
// done() is needed because the testharness is running as if explicit_done
|
||||
// was specified.
|
||||
done();
|
||||
|
||||
`test.html`:
|
||||
|
||||
<!DOCTYPE html>
|
||||
<title>Simple test</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
|
||||
fetch_tests_from_worker(new Worker("worker.js"));
|
||||
|
||||
</script>
|
||||
|
||||
The argument to the `fetch_tests_from_worker` function can be a
|
||||
[`Worker`](https://html.spec.whatwg.org/multipage/workers.html#dedicated-workers-and-the-worker-interface),
|
||||
a [`SharedWorker`](https://html.spec.whatwg.org/multipage/workers.html#shared-workers-and-the-sharedworker-interface)
|
||||
or a [`ServiceWorker`](https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-obj).
|
||||
Once called, the containing document fetches all the tests from the worker and
|
||||
behaves as if those tests were running in the containing document itself.
|
||||
|
||||
## List of Assertions ##
|
||||
|
||||
### `assert_true(actual, description)`
|
||||
asserts that `actual` is strictly true
|
||||
|
||||
### `assert_false(actual, description)`
|
||||
asserts that `actual` is strictly false
|
||||
|
||||
### `assert_equals(actual, expected, description)`
|
||||
asserts that `actual` is the same value as `expected`
|
||||
|
||||
### `assert_not_equals(actual, expected, description)`
|
||||
asserts that `actual` is a different value to `expected`.
|
||||
This means that `expected` is a misnomer.
|
||||
|
||||
### `assert_in_array(actual, expected, description)`
|
||||
asserts that `expected` is an Array, and `actual` is equal to one of the
|
||||
members i.e. `expected.indexOf(actual) != -1`
|
||||
|
||||
### `assert_array_equals(actual, expected, description)`
|
||||
asserts that `actual` and `expected` have the same
|
||||
length and the value of each indexed property in `actual` is the strictly equal
|
||||
to the corresponding property value in `expected`
|
||||
|
||||
### `assert_approx_equals(actual, expected, epsilon, description)`
|
||||
asserts that `actual` is a number within +`- `epsilon` of `expected`
|
||||
|
||||
### `assert_less_than(actual, expected, description)`
|
||||
asserts that `actual` is a number less than `expected`
|
||||
|
||||
### `assert_greater_than(actual, expected, description)`
|
||||
asserts that `actual` is a number greater than `expected`
|
||||
|
||||
### `assert_between_exclusive(actual, lower, upper, description`
|
||||
asserts that `actual` is a number between `lower` and `upper` but not
|
||||
equal to either of them
|
||||
|
||||
### `assert_less_than_equal(actual, expected, description)`
|
||||
asserts that `actual` is a number less than or equal to `expected`
|
||||
|
||||
### `assert_greater_than_equal(actual, expected, description)`
|
||||
asserts that `actual` is a number greater than or equal to `expected`
|
||||
|
||||
### `assert_between_inclusive(actual, lower, upper, description`
|
||||
asserts that `actual` is a number between `lower` and `upper` or
|
||||
equal to either of them
|
||||
|
||||
### `assert_regexp_match(actual, expected, description)`
|
||||
asserts that `actual` matches the regexp `expected`
|
||||
|
||||
### `assert_class_string(object, class_name, description)`
|
||||
asserts that the class string of `object` as returned in
|
||||
`Object.prototype.toString` is equal to `class_name`.
|
||||
|
||||
### `assert_own_property(object, property_name, description)`
|
||||
assert that object has own property `property_name`
|
||||
|
||||
### `assert_inherits(object, property_name, description)`
|
||||
assert that object does not have an own property named
|
||||
`property_name` but that `property_name` is present in the prototype
|
||||
chain for object
|
||||
|
||||
### `assert_idl_attribute(object, attribute_name, description)`
|
||||
assert that an object that is an instance of some interface has the
|
||||
attribute attribute_name following the conditions specified by WebIDL
|
||||
|
||||
### `assert_readonly(object, property_name, description)`
|
||||
assert that property `property_name` on object is readonly
|
||||
|
||||
### `assert_throws(code, func, description)`
|
||||
`code` - the expected exception. This can take several forms:
|
||||
|
||||
* string - the thrown exception must be a DOMException with the given
|
||||
name, e.g., "TimeoutError" (for compatibility with existing
|
||||
tests, a constant is also supported, e.g., "TIMEOUT_ERR")
|
||||
* object - the thrown exception must have a property called "name" that
|
||||
matches code.name
|
||||
* null - allow any exception (in general, one of the options above
|
||||
should be used)
|
||||
|
||||
`func` - a function that should throw
|
||||
|
||||
### `assert_unreached(description)`
|
||||
asserts if called. Used to ensure that some codepath is *not* taken e.g.
|
||||
an event does not fire.
|
||||
|
||||
### `assert_any(assert_func, actual, expected_array, extra_arg_1, ... extra_arg_N)`
|
||||
asserts that one `assert_func(actual, expected_array_N, extra_arg1, ..., extra_arg_N)`
|
||||
is true for some `expected_array_N` in `expected_array`. This only works for `assert_func`
|
||||
with signature `assert_func(actual, expected, args_1, ..., args_N)`. Note that tests
|
||||
with multiple allowed pass conditions are bad practice unless the spec specifically
|
||||
allows multiple behaviours. Test authors should not use this method simply to hide
|
||||
UA bugs.
|
||||
|
||||
### `assert_exists(object, property_name, description)`
|
||||
**deprecated**
|
||||
asserts that object has an own property `property_name`
|
||||
|
||||
### `assert_not_exists(object, property_name, description)`
|
||||
**deprecated**
|
||||
assert that object does not have own property `property_name`
|
||||
|
||||
## Metadata ##
|
||||
|
||||
It is possible to add optional metadata to tests; this can be done in
|
||||
one of two ways; either by adding `<meta>` elements to the head of the
|
||||
document containing the tests, or by adding the metadata to individual
|
||||
`[async_]test` calls, as properties.
|
118
tests/wpt/web-platform-tests/resources/docs/idlharness.md
Normal file
118
tests/wpt/web-platform-tests/resources/docs/idlharness.md
Normal file
|
@ -0,0 +1,118 @@
|
|||
## Introduction ##
|
||||
|
||||
`idlharness.js` automatically generates browser tests for WebIDL interfaces, using
|
||||
the testharness.js framework. To use, first include the following:
|
||||
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=/resources/WebIDLParser.js></script>
|
||||
<script src=/resources/idlharness.js></script>
|
||||
|
||||
Then you'll need some type of IDLs. Here's some script that can be run on a
|
||||
spec written in HTML, which will grab all the elements with `class="idl"`,
|
||||
concatenate them, and replace the body so you can copy-paste:
|
||||
|
||||
var s = "";
|
||||
[].forEach.call(document.getElementsByClassName("idl"), function(idl) {
|
||||
//https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914
|
||||
if (!idl.classList.contains("extract"))
|
||||
{
|
||||
s += idl.textContent + "\n\n";
|
||||
}
|
||||
});
|
||||
document.body.innerHTML = '<pre></pre>';
|
||||
document.body.firstChild.textContent = s;
|
||||
|
||||
Once you have that, put it in your script somehow. The easiest way is to
|
||||
embed it literally in an HTML file with `<script type=text/plain>` or similar,
|
||||
so that you don't have to do any escaping. Another possibility is to put it
|
||||
in a separate .idl file that's fetched via XHR or similar. Sample usage:
|
||||
|
||||
var idl_array = new IdlArray();
|
||||
idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };");
|
||||
idl_array.add_idls("interface Document : Node { readonly attribute DOMString URL; };");
|
||||
idl_array.add_objects({Document: ["document"]});
|
||||
idl_array.test();
|
||||
|
||||
This tests that `window.Document` exists and meets all the requirements of
|
||||
WebIDL. It also tests that window.document (the result of evaluating the
|
||||
string "document") has URL and nodeName properties that behave as they
|
||||
should, and otherwise meets WebIDL's requirements for an object whose
|
||||
primary interface is Document. It does not test that window.Node exists,
|
||||
which is what you want if the Node interface is already tested in some other
|
||||
specification's suite and your specification only extends or refers to it.
|
||||
Of course, each IDL string can define many different things, and calls to
|
||||
add_objects() can register many different objects for different interfaces:
|
||||
this is a very simple example.
|
||||
|
||||
## Public methods of IdlArray ##
|
||||
|
||||
IdlArray objects can be obtained with `new IdlArray()`. Anything not
|
||||
documented in this section should be considered an implementation detail,
|
||||
and outside callers should not use it.
|
||||
|
||||
### `add_idls(idl_string)`
|
||||
Parses `idl_string` (throwing on parse error) and adds the results to the
|
||||
IdlArray. All the definitions will be tested when you run test(). If
|
||||
some of the definitions refer to other definitions, those must be present
|
||||
too. For instance, if `idl_string` says that `Document` inherits from `Node`,
|
||||
the `Node` interface must also have been provided in some call to `add_idls()`
|
||||
or `add_untested_idls()`.
|
||||
|
||||
### `add_untested_idls(idl_string)`
|
||||
Like `add_idls()`, but the definitions will not be tested. If an untested
|
||||
interface is added and then extended with a tested partial interface, the
|
||||
members of the partial interface will still be tested. Also, all the
|
||||
members will still be tested for objects added with `add_objects()`, because
|
||||
you probably want to test that (for instance) window.document has all the
|
||||
properties from `Node`, not just `Document`, even if the `Node` interface itself
|
||||
is tested in a different test suite.
|
||||
|
||||
### `add_objects(dict)`
|
||||
`dict` should be an object whose keys are the names of interfaces or
|
||||
exceptions, and whose values are arrays of strings. When an interface or
|
||||
exception is tested, every string registered for it with `add_objects()`
|
||||
will be evaluated, and tests will be run on the result to verify that it
|
||||
correctly implements that interface or exception. This is the only way to
|
||||
test anything about `[NoInterfaceObject]` interfaces, and there are many
|
||||
tests that can't be run on any interface without an object to fiddle with.
|
||||
|
||||
The interface has to be the *primary* interface of all the objects
|
||||
provided. For example, don't pass `{Node: ["document"]}`, but rather
|
||||
`{Document: ["document"]}`. Assuming the `Document` interface was declared to
|
||||
inherit from `Node`, this will automatically test that document implements
|
||||
the `Node` interface too.
|
||||
|
||||
Warning: methods will be called on any provided objects, in a manner that
|
||||
WebIDL requires be safe. For instance, if a method has mandatory
|
||||
arguments, the test suite will try calling it with too few arguments to
|
||||
see if it throws an exception. If an implementation incorrectly runs the
|
||||
function instead of throwing, this might have side effects, possibly even
|
||||
preventing the test suite from running correctly.
|
||||
|
||||
### `prevent_multiple_testing(name)`
|
||||
This is a niche method for use in case you're testing many objects that
|
||||
implement the same interfaces, and don't want to retest the same
|
||||
interfaces every single time. For instance, HTML defines many interfaces
|
||||
that all inherit from `HTMLElement`, so the HTML test suite has something
|
||||
like
|
||||
`.add_objects({
|
||||
HTMLHtmlElement: ['document.documentElement'],
|
||||
HTMLHeadElement: ['document.head'],
|
||||
HTMLBodyElement: ['document.body'],
|
||||
...
|
||||
})`
|
||||
and so on for dozens of element types. This would mean that it would
|
||||
retest that each and every one of those elements implements `HTMLElement`,
|
||||
`Element`, and `Node`, which would be thousands of basically redundant tests.
|
||||
The test suite therefore calls `prevent_multiple_testing("HTMLElement")`.
|
||||
This means that once one object has been tested to implement `HTMLElement`
|
||||
and its ancestors, no other object will be. Thus in the example code
|
||||
above, the harness would test that `document.documentElement` correctly
|
||||
implements `HTMLHtmlElement`, `HTMLElement`, `Element`, and `Node`; but
|
||||
`document.head` would only be tested for `HTMLHeadElement`, and so on for
|
||||
further objects.
|
||||
|
||||
### `test()`
|
||||
Run all tests. This should be called after you've called all other
|
||||
methods to add IDLs and objects.
|
1636
tests/wpt/web-platform-tests/resources/idlharness.js
Normal file
1636
tests/wpt/web-platform-tests/resources/idlharness.js
Normal file
File diff suppressed because it is too large
Load diff
23
tests/wpt/web-platform-tests/resources/readme.md
Normal file
23
tests/wpt/web-platform-tests/resources/readme.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
## Introdution ##
|
||||
|
||||
testharness.js provides a framework for writing low-level tests of
|
||||
browser functionality in javascript. It provides a convenient API for
|
||||
making assertions and is intended to work for both simple synchronous
|
||||
tests and for tests of asynchronous behaviour.
|
||||
|
||||
## Getting Started ##
|
||||
|
||||
To use testharness.js you must include two scripts, in the order given:
|
||||
|
||||
``` html
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
```
|
||||
|
||||
## Full documentation ##
|
||||
|
||||
Full user documentation for the API is in the
|
||||
[docs/api.md](https://github.com/w3c/testharness.js/blob/master/docs/api.md) file.
|
||||
|
||||
You can also read a tutorial on
|
||||
[Using testharness.js](http://darobin.github.com/test-harness-tutorial/docs/using-testharness.html).
|
102
tests/wpt/web-platform-tests/resources/testharness.css
Normal file
102
tests/wpt/web-platform-tests/resources/testharness.css
Normal file
|
@ -0,0 +1,102 @@
|
|||
html {
|
||||
font-family:DejaVu Sans, Bitstream Vera Sans, Arial, Sans;
|
||||
}
|
||||
|
||||
#log .warning,
|
||||
#log .warning a {
|
||||
color: black;
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
#log .error,
|
||||
#log .error a {
|
||||
color: white;
|
||||
background: red;
|
||||
}
|
||||
|
||||
section#summary {
|
||||
margin-bottom:1em;
|
||||
}
|
||||
|
||||
table#results {
|
||||
border-collapse:collapse;
|
||||
table-layout:fixed;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
table#results th:first-child,
|
||||
table#results td:first-child {
|
||||
width:4em;
|
||||
}
|
||||
|
||||
table#results th:last-child,
|
||||
table#results td:last-child {
|
||||
width:50%;
|
||||
}
|
||||
|
||||
table#results.assertions th:last-child,
|
||||
table#results.assertions td:last-child {
|
||||
width:35%;
|
||||
}
|
||||
|
||||
table#results th {
|
||||
padding:0;
|
||||
padding-bottom:0.5em;
|
||||
border-bottom:medium solid black;
|
||||
}
|
||||
|
||||
table#results td {
|
||||
padding:1em;
|
||||
padding-bottom:0.5em;
|
||||
border-bottom:thin solid black;
|
||||
}
|
||||
|
||||
tr.pass > td:first-child {
|
||||
color:green;
|
||||
}
|
||||
|
||||
tr.fail > td:first-child {
|
||||
color:red;
|
||||
}
|
||||
|
||||
tr.timeout > td:first-child {
|
||||
color:red;
|
||||
}
|
||||
|
||||
tr.notrun > td:first-child {
|
||||
color:blue;
|
||||
}
|
||||
|
||||
.pass > td:first-child, .fail > td:first-child, .timeout > td:first-child, .notrun > td:first-child {
|
||||
font-variant:small-caps;
|
||||
}
|
||||
|
||||
table#results span {
|
||||
display:block;
|
||||
}
|
||||
|
||||
table#results span.expected {
|
||||
font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace;
|
||||
white-space:pre;
|
||||
}
|
||||
|
||||
table#results span.actual {
|
||||
font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace;
|
||||
white-space:pre;
|
||||
}
|
||||
|
||||
span.ok {
|
||||
color:green;
|
||||
}
|
||||
|
||||
tr.error {
|
||||
color:red;
|
||||
}
|
||||
|
||||
span.timeout {
|
||||
color:red;
|
||||
}
|
||||
|
||||
span.ok, span.timeout, span.error {
|
||||
font-variant:small-caps;
|
||||
}
|
2427
tests/wpt/web-platform-tests/resources/testharness.js
Normal file
2427
tests/wpt/web-platform-tests/resources/testharness.js
Normal file
File diff suppressed because it is too large
Load diff
21
tests/wpt/web-platform-tests/resources/testharnessreport.js
Normal file
21
tests/wpt/web-platform-tests/resources/testharnessreport.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var props = {output:%(output)d,
|
||||
explicit_timeout: true};
|
||||
|
||||
if (window.opener && "timeout_multiplier" in window.opener) {
|
||||
props["timeout_multiplier"] = window.opener.timeout_multiplier;
|
||||
}
|
||||
|
||||
if (window.opener && window.opener.explicit_timeout) {
|
||||
props["explicit_timeout"] = window.opener.explicit_timeout;
|
||||
}
|
||||
|
||||
setup(props);
|
||||
add_completion_callback(function() {
|
||||
add_completion_callback(function(tests, status) {
|
||||
window.opener.done(tests, status)
|
||||
})
|
||||
});
|
4
tests/wpt/web-platform-tests/resources/webidl2/.gitignore
vendored
Normal file
4
tests/wpt/web-platform-tests/resources/webidl2/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
scratch
|
||||
node_modules
|
||||
lib-cov
|
||||
browser-tests.html
|
3
tests/wpt/web-platform-tests/resources/webidl2/.gitmodules
vendored
Normal file
3
tests/wpt/web-platform-tests/resources/webidl2/.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "test/widlproc"]
|
||||
path = test/widlproc
|
||||
url = https://github.com/dontcallmedom/widlproc.git
|
|
@ -0,0 +1,3 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
725
tests/wpt/web-platform-tests/resources/webidl2/README.md
Normal file
725
tests/wpt/web-platform-tests/resources/webidl2/README.md
Normal file
|
@ -0,0 +1,725 @@
|
|||
|
||||
# WebIDL 2
|
||||
|
||||
[](http://badge.fury.io/js/webidl2)
|
||||
|
||||
Purpose
|
||||
=======
|
||||
|
||||
This is a parser for the [WebIDL](http://dev.w3.org/2006/webapi/WebIDL/) language. If
|
||||
you don't know what that is, then you probably don't need it. It is meant to be used
|
||||
both in Node and in the browser (the parser likely works in other JS environments, but
|
||||
not the test suite).
|
||||
|
||||
What of v1?
|
||||
-----------
|
||||
There was a previous incarnation of this project. I had written it in the most quick
|
||||
and dirty manner that was handy because I required it as a dependency in an experiment.
|
||||
As these things tend to happen, some people started using that, which then had to be
|
||||
maintained. But since it was not built on solid foundations, it was painful to keep
|
||||
up to date with the specification, which is a bit of a moving target.
|
||||
|
||||
So I started from scratch. Compared to the previous version (which used a parser generator)
|
||||
this one is about 6x less code (which translates to 4x smaller minified or 2x smaller
|
||||
minizipped) and 4x faster. The test suite is reasonably complete (95% coverage), much more
|
||||
than previously. This version is up to date with WebIDL, rather than a couple years' behind.
|
||||
It also has *far* better error reporting.
|
||||
|
||||
The AST you get from parsing is very similar to the one you got in v1, but some adjustments
|
||||
have been made in order to be more systematic, and to map better to what's actually in the spec
|
||||
now. If you used v1, you will need to tweak your code but the result ought to be simpler and
|
||||
you ought to be able to be a fair bit less defensive against irregularities in the way
|
||||
information is represented.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Just the usual. For Node:
|
||||
|
||||
npm install webidl2
|
||||
|
||||
In the browser:
|
||||
|
||||
<script src='webidl2.js'></script>
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
The API to WebIDL2 is trivial: you parse a string of WebIDL and it returns a syntax tree.
|
||||
|
||||
Parsing
|
||||
-------
|
||||
In Node, that happens with:
|
||||
|
||||
var WebIDL2 = require("webidl2");
|
||||
var tree = WebIDL2.parse("string of WebIDL");
|
||||
|
||||
In the browser:
|
||||
|
||||
<script src='webidl2.js'></script>
|
||||
<script>
|
||||
var tree = WebIDL2.parse("string of WebIDL");
|
||||
</script>
|
||||
|
||||
Errors
|
||||
------
|
||||
When there is a syntax error in the WebIDL, it throws an exception object with the following
|
||||
properties:
|
||||
|
||||
* `message`: the error message
|
||||
* `line`: the line at which the error occurred.
|
||||
* `input`: a short peek at the text at the point where the error happened
|
||||
* `tokens`: the five tokens at the point of error, as understood by the tokeniser
|
||||
(this is the same content as `input`, but seen from the tokeniser's point of view)
|
||||
|
||||
The exception also has a `toString()` method that hopefully should produce a decent
|
||||
error message.
|
||||
|
||||
AST (Abstract Syntax Tree)
|
||||
--------------------------
|
||||
The `parse()` method returns a tree object representing the parse tree of the IDL.
|
||||
Comment and white space are not represented in the AST.
|
||||
|
||||
The root of this object is always an array of definitions (where definitions are
|
||||
any of interfaces, exceptions, callbacks, etc. — anything that can occur at the root
|
||||
of the IDL).
|
||||
|
||||
### IDL Type
|
||||
|
||||
This structure is used in many other places (operation return types, argument types, etc.).
|
||||
It captures a WebIDL type with a number of options. Types look like this and are typically
|
||||
attached to a field called `idlType`:
|
||||
|
||||
{
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "void"
|
||||
}
|
||||
|
||||
Where the fields are as follows:
|
||||
|
||||
* `sequence`: Boolean indicating whether this is a sequence or not. Deprecated. Use
|
||||
`generic` instead.
|
||||
* `generic`: String indicating the generic type (e.g. "Promise", "sequence"). `null`
|
||||
otherwise.
|
||||
* `nullable`: Boolean indicating whether this is nullable or not.
|
||||
* `array`: Either `false` to indicate that it is not an array, or a number for the level of
|
||||
array nesting.
|
||||
* `union`: Boolean indicating whether this is a union type or not.
|
||||
* `idlType`: Can be different things depending on context. In most cases, this will just
|
||||
be a string with the type name. But the reason this field isn't called "typeName" is
|
||||
because it can take more complex values. If the type is a union, then this contains an
|
||||
array of the types it unites. If it is a generic type, it contains the IDL type
|
||||
description for the type in the sequence, the eventual value of the promise, etc.
|
||||
|
||||
#### Interactions between `nullable` and `array`
|
||||
|
||||
A more complex data model for our AST would likely represent `Foo[][][]` as a series of
|
||||
nested types four levels deep with three anonymous array types eventually containing a
|
||||
`Foo` type. But experience shows that such structures are cumbersome to use, and so we
|
||||
have a simpler model in which the depth of the array is specified with the `array` field.
|
||||
|
||||
This is all fine and well, and in the vast majority of cases is actually simpler. But it
|
||||
does run afoul of cases in which it is necessary to distinguish between `Foo[][][]?`,
|
||||
`Foo?[][][]`, `Foo[][]?[]`, or even `Foo?[]?[]?[]?`.
|
||||
|
||||
For this, when a type is an array type an additional `nullableArray` field is made available
|
||||
that captures which of the arrays contain nullable elements. It contains booleans that are
|
||||
true if the given array depth contains nullable elements, and false otherwise (mapping that to
|
||||
the syntax, and item is true if there is a `?` preceding the `[]`). These examples ought to
|
||||
clarify the model:
|
||||
|
||||
Foo[][][]?
|
||||
-> nullable: true
|
||||
-> nullableArray: [false, false, false]
|
||||
Foo?[][][]
|
||||
-> nullable: false
|
||||
-> nullableArray: [true, false, false]
|
||||
Foo[][]?[]
|
||||
-> nullable: false
|
||||
-> nullableArray: [false, false, true]
|
||||
Foo?[]?[]?[]?
|
||||
-> nullable: true
|
||||
-> nullableArray: [true, true, true]
|
||||
|
||||
Of particular importance, please note that the overall type is only `nullable` if there is
|
||||
a `?` at the end.
|
||||
|
||||
### Interface
|
||||
Interfaces look like this:
|
||||
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "Animal",
|
||||
"partial": false,
|
||||
"members": [...],
|
||||
"inheritance": null,
|
||||
"extAttrs": [...]
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "Human",
|
||||
"partial": false,
|
||||
"members": [...],
|
||||
"inheritance": "Animal",
|
||||
"extAttrs": [...]
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "interface".
|
||||
* `name`: The name of the interface
|
||||
* `partial`: A boolean indicating whether it's a partial interface.
|
||||
* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none.
|
||||
* `inheritance`: A string giving the name of an interface this one inherits from, `null` otherwise.
|
||||
**NOTE**: In v1 this was an array, but multiple inheritance is no longer supported so this didn't make
|
||||
sense.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Callback Interfaces
|
||||
|
||||
These are captured by the same structure as [Interfaces](#interface) except that
|
||||
their `type` field is "callback interface".
|
||||
|
||||
### Callback
|
||||
|
||||
A callback looks like this:
|
||||
|
||||
{
|
||||
"type": "callback",
|
||||
"name": "AsyncOperationCallback",
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "void"
|
||||
},
|
||||
"arguments": [...],
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "callback".
|
||||
* `name`: The name of the callback.
|
||||
* `idlType`: An [IDL Type](#idl-type) describing what the callback returns.
|
||||
* `arguments`: A list of [arguments](#arguments), as in function paramters.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Dictionary
|
||||
|
||||
A dictionary looks like this:
|
||||
|
||||
{
|
||||
"type": "dictionary",
|
||||
"name": "PaintOptions",
|
||||
"partial": false,
|
||||
"members": [
|
||||
{
|
||||
"type": "field",
|
||||
"name": "fillPattern",
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": true,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "DOMString"
|
||||
},
|
||||
"extAttrs": [],
|
||||
"default": {
|
||||
"type": "string",
|
||||
"value": "black"
|
||||
}
|
||||
}
|
||||
],
|
||||
"inheritance": null,
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "dictionary".
|
||||
* `name`: The dictionary name.
|
||||
* `partial`: Boolean indicating whether it's a partial dictionary.
|
||||
* `members`: An array of members (see below).
|
||||
* `inheritance`: A string indicating which dictionary is being inherited from, `null` otherwise.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
All the members are fields as follows:
|
||||
|
||||
* `type`: Always "field".
|
||||
* `name`: The name of the field.
|
||||
* `idlType`: An [IDL Type](#idl-type) describing what field's type.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
* `default`: A [default value](#default-and-const-values), absent if there is none.
|
||||
|
||||
### Exception
|
||||
|
||||
An exception looks like this:
|
||||
|
||||
{
|
||||
"type": "exception",
|
||||
"name": "HierarchyRequestError",
|
||||
"members": [
|
||||
{
|
||||
"type": "field",
|
||||
"name": "code",
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "unsigned short"
|
||||
},
|
||||
"extAttrs": []
|
||||
}
|
||||
],
|
||||
"inheritance": "DOMException",
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "exception".
|
||||
* `name`: The exception name.
|
||||
* `members`: An array of members (constants or fields, where fields are described below).
|
||||
* `inheritance`: A string indicating which exception is being inherited from, `null` otherwise.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
Members that aren't [constants](#constants) have the following fields:
|
||||
|
||||
* `type`: Always "field".
|
||||
* `name`: The field's name.
|
||||
* `idlType`: An [IDL Type](#idl-type) describing what field's type.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Enum
|
||||
|
||||
An enum looks like this:
|
||||
|
||||
{
|
||||
"type": "enum",
|
||||
"name": "MealType",
|
||||
"values": [
|
||||
"rice",
|
||||
"noodles",
|
||||
"other"
|
||||
],
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "enum".
|
||||
* `name`: The enum's name.
|
||||
* `value`: An array of values (strings).
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Typedef
|
||||
|
||||
A typedef looks like this:
|
||||
|
||||
{
|
||||
"type": "typedef",
|
||||
"typeExtAttrs": [],
|
||||
"idlType": {
|
||||
"sequence": true,
|
||||
"generic": "sequence",
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "Point"
|
||||
}
|
||||
},
|
||||
"name": "PointSequence",
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "typedef".
|
||||
* `name`: The typedef's name.
|
||||
* `idlType`: An [IDL Type](#idl-type) describing what typedef's type.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
* `typeExtAttrs`: A list of [extended attributes](#extended-attributes) that apply to the
|
||||
type rather than to the typedef as a whole.
|
||||
|
||||
### Implements
|
||||
|
||||
An implements definition looks like this:
|
||||
|
||||
{
|
||||
"type": "implements",
|
||||
"target": "Node",
|
||||
"implements": "EventTarget",
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "implements".
|
||||
* `target`: The interface that implements another.
|
||||
* `implements`: The interface that is being implemented by the target.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Operation Member
|
||||
|
||||
An operation looks like this:
|
||||
|
||||
{
|
||||
"type": "operation",
|
||||
"getter": false,
|
||||
"setter": false,
|
||||
"creator": false,
|
||||
"deleter": false,
|
||||
"legacycaller": false,
|
||||
"static": false,
|
||||
"stringifier": false,
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "void"
|
||||
},
|
||||
"name": "intersection",
|
||||
"arguments": [
|
||||
{
|
||||
"optional": false,
|
||||
"variadic": true,
|
||||
"extAttrs": [],
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "long"
|
||||
},
|
||||
"name": "ints"
|
||||
}
|
||||
],
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "operation".
|
||||
* `getter`: True if a getter operation.
|
||||
* `setter`: True if a setter operation.
|
||||
* `creator`: True if a creator operation.
|
||||
* `deleter`: True if a deleter operation.
|
||||
* `legacycaller`: True if a legacycaller operation.
|
||||
* `static`: True if a static operation.
|
||||
* `stringifier`: True if a stringifier operation.
|
||||
* `idlType`: An [IDL Type](#idl-type) of what the operation returns. If a stringifier, may be absent.
|
||||
* `name`: The name of the operation. If a stringifier, may be `null`.
|
||||
* `arguments`: An array of [arguments](#arguments) for the operation.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Attribute Member
|
||||
|
||||
An attribute member looks like this:
|
||||
|
||||
{
|
||||
"type": "attribute",
|
||||
"static": false,
|
||||
"stringifier": false,
|
||||
"inherit": false,
|
||||
"readonly": false,
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "RegExp"
|
||||
},
|
||||
"name": "regexp",
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "attribute".
|
||||
* `name`: The attribute's name.
|
||||
* `static`: True if it's a static attribute.
|
||||
* `stringifier`: True if it's a stringifier attribute.
|
||||
* `inherit`: True if it's an inherit attribute.
|
||||
* `readonly`: True if it's a read-only attribute.
|
||||
* `idlType`: An [IDL Type](#idl-type) for the attribute.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Constant Member
|
||||
|
||||
A constant member looks like this:
|
||||
|
||||
{
|
||||
"type": "const",
|
||||
"nullable": false,
|
||||
"idlType": "boolean",
|
||||
"name": "DEBUG",
|
||||
"value": {
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `type`: Always "const".
|
||||
* `nullable`: Whether its type is nullable.
|
||||
* `idlType`: The type of the constant (a simple type, the type name).
|
||||
* `name`: The name of the constant.
|
||||
* `value`: The constant value as described by [Const Values](#default-and-const-values)
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Serializer Member
|
||||
|
||||
Serializers come in many shapes, which are best understood by looking at the
|
||||
examples below that map the IDL to the produced AST.
|
||||
|
||||
// serializer;
|
||||
{
|
||||
"type": "serializer",
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
// serializer DOMString serialize();
|
||||
{
|
||||
"type": "serializer",
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "DOMString"
|
||||
},
|
||||
"operation": {
|
||||
"name": "serialize",
|
||||
"arguments": []
|
||||
},
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
// serializer = { from, to, amount, description };
|
||||
{
|
||||
"type": "serializer",
|
||||
"patternMap": true,
|
||||
"names": [
|
||||
"from",
|
||||
"to",
|
||||
"amount",
|
||||
"description"
|
||||
],
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
// serializer = number;
|
||||
{
|
||||
"type": "serializer",
|
||||
"name": "number",
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
// serializer = [ name, number ];
|
||||
{
|
||||
"type": "serializer",
|
||||
"patternList": true,
|
||||
"names": [
|
||||
"name",
|
||||
"number"
|
||||
],
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
The common fields are as follows:
|
||||
|
||||
* `type`: Always "serializer".
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
For a simple serializer, that's all there is. If the serializer is an operation, it will
|
||||
have:
|
||||
|
||||
* `idlType`: An [IDL Type](#idl-type) describing what the serializer returns.
|
||||
* `operation`: An object with the following fields:
|
||||
* `name`: The name of the operation.
|
||||
* `arguments`: An array of [arguments](#arguments) for the operation.
|
||||
|
||||
If the serializer is a pattern map:
|
||||
|
||||
* `patternMap`: Always true.
|
||||
* `names`: An array of names in the pattern map.
|
||||
|
||||
If the serializer is a pattern list:
|
||||
|
||||
* `patternList`: Always true.
|
||||
* `names`: An array of names in the pattern list.
|
||||
|
||||
Finally, if the serializer is a named serializer:
|
||||
|
||||
* `name`: The serializer's name.
|
||||
|
||||
### Iterator Member
|
||||
|
||||
Iterator members look like this
|
||||
|
||||
{
|
||||
"type": "iterator",
|
||||
"getter": false,
|
||||
"setter": false,
|
||||
"creator": false,
|
||||
"deleter": false,
|
||||
"legacycaller": false,
|
||||
"static": false,
|
||||
"stringifier": false,
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "Session2"
|
||||
},
|
||||
"iteratorObject": "SessionIterator",
|
||||
"extAttrs": []
|
||||
}
|
||||
|
||||
* `type`: Always "iterator".
|
||||
* `iteratorObject`: The string on the right-hand side; absent if there isn't one.
|
||||
* the rest: same as on [operations](#operation-member).
|
||||
|
||||
### Arguments
|
||||
|
||||
The arguments (e.g. for an operation) look like this:
|
||||
|
||||
"arguments": [
|
||||
{
|
||||
"optional": false,
|
||||
"variadic": true,
|
||||
"extAttrs": [],
|
||||
"idlType": {
|
||||
"sequence": false,
|
||||
"generic": null,
|
||||
"nullable": false,
|
||||
"array": false,
|
||||
"union": false,
|
||||
"idlType": "long"
|
||||
},
|
||||
"name": "ints"
|
||||
}
|
||||
]
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `optional`: True if the argument is optional.
|
||||
* `variadic`: True if the argument is variadic.
|
||||
* `idlType`: An [IDL Type](#idl-type) describing the type of the argument.
|
||||
* `name`: The argument's name.
|
||||
* `extAttrs`: A list of [extended attributes](#extended-attributes).
|
||||
|
||||
### Extended Attributes
|
||||
|
||||
Extended attributes are arrays of items that look like this:
|
||||
|
||||
"extAttrs": [
|
||||
{
|
||||
"name": "TreatNullAs",
|
||||
"arguments": null,
|
||||
"rhs": {
|
||||
"type": "identifier",
|
||||
"value": "EmptyString"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
* `name`: The extended attribute's name.
|
||||
* `arguments`: If the extended attribute takes arguments (e.g. `[Foo()]`) or if
|
||||
its right-hand side does (e.g. `[NamedConstructor=Name(DOMString blah)]`) they
|
||||
are listed here. Note that an empty arguments list will produce an empty array,
|
||||
whereas the lack thereof will yield a `null`. If there is an `rhs` field then
|
||||
they are the right-hand side's arguments, otherwise they apply to the extended
|
||||
attribute directly.
|
||||
* `rhs`: If there is a right-hand side, this will capture its `type` (always
|
||||
"identifier" in practice, though it may be extended in the future) and its
|
||||
`value`.
|
||||
* `typePair`: If the extended attribute is a `MapClass` this will capture the
|
||||
map's key type and value type respectively.
|
||||
|
||||
### Default and Const Values
|
||||
|
||||
Dictionary fields and operation arguments can take default values, and constants take
|
||||
values, all of which have the following fields:
|
||||
|
||||
* `type`: One of string, number, boolean, null, Infinity, or NaN.
|
||||
|
||||
For string, number, and boolean:
|
||||
|
||||
* `value`: The value of the given type.
|
||||
|
||||
For Infinity:
|
||||
|
||||
* `negative`: Boolean indicating whether this is negative Infinity or not.
|
||||
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
In order to run the tests you need to ensure that the widlproc submodule inside `test` is
|
||||
initialised and up to date:
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
Running
|
||||
-------
|
||||
The test runs with mocha and expect.js. Normally, running mocha in the root directory
|
||||
should be enough once you're set up.
|
||||
|
||||
Coverage
|
||||
--------
|
||||
Current test coverage, as documented in `coverage.html`, is 95%. You can run your own
|
||||
coverage analysis with:
|
||||
|
||||
jscoverage lib lib-cov
|
||||
|
||||
That will create the lib-cov directory with instrumented code; the test suite knows
|
||||
to use that if needed. You can then run the tests with:
|
||||
|
||||
JSCOV=1 mocha --reporter html-cov > coverage.html
|
||||
|
||||
Note that I've been getting weirdly overescaped results from the html-cov reporter,
|
||||
so you might wish to try this instead:
|
||||
|
||||
JSCOV=1 mocha --reporter html-cov | sed "s/</</g" | sed "s/>/>/g" | sed "s/"/\"/g" > coverage.html
|
||||
|
||||
Browser tests
|
||||
-------------
|
||||
In order to test in the browser, get inside `test/web` and run `make-web-tests.js`. This
|
||||
will generate a `browser-tests.html` file that you can open in a browser. As of this
|
||||
writing tests pass in the latest Firefox, Chrome, Opera, and Safari. Testing on IE
|
||||
and older versions will happen progressively.
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
* add some tests to address coverage limitations
|
||||
* add a push API for processors that need to process things like comments
|
341
tests/wpt/web-platform-tests/resources/webidl2/coverage.html
Normal file
341
tests/wpt/web-platform-tests/resources/webidl2/coverage.html
Normal file
File diff suppressed because one or more lines are too long
1
tests/wpt/web-platform-tests/resources/webidl2/index.js
Normal file
1
tests/wpt/web-platform-tests/resources/webidl2/index.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = require("./lib/webidl2.js");
|
924
tests/wpt/web-platform-tests/resources/webidl2/lib/webidl2.js
Normal file
924
tests/wpt/web-platform-tests/resources/webidl2/lib/webidl2.js
Normal file
|
@ -0,0 +1,924 @@
|
|||
|
||||
|
||||
(function () {
|
||||
var tokenise = function (str) {
|
||||
var tokens = []
|
||||
, re = {
|
||||
"float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/
|
||||
, "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/
|
||||
, "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/
|
||||
, "string": /^"[^"]*"/
|
||||
, "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/
|
||||
, "other": /^[^\t\n\r 0-9A-Z_a-z]/
|
||||
}
|
||||
, types = []
|
||||
;
|
||||
for (var k in re) types.push(k);
|
||||
while (str.length > 0) {
|
||||
var matched = false;
|
||||
for (var i = 0, n = types.length; i < n; i++) {
|
||||
var type = types[i];
|
||||
str = str.replace(re[type], function (tok) {
|
||||
tokens.push({ type: type, value: tok });
|
||||
matched = true;
|
||||
return "";
|
||||
});
|
||||
if (matched) break;
|
||||
}
|
||||
if (matched) continue;
|
||||
throw new Error("Token stream not progressing");
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
|
||||
var parse = function (tokens, opt) {
|
||||
var line = 1;
|
||||
tokens = tokens.slice();
|
||||
|
||||
var FLOAT = "float"
|
||||
, INT = "integer"
|
||||
, ID = "identifier"
|
||||
, STR = "string"
|
||||
, OTHER = "other"
|
||||
;
|
||||
|
||||
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 + ", line " + this.line + " (tokens: '" + this.input + "')\n" +
|
||||
JSON.stringify(this.tokens, null, 4);
|
||||
};
|
||||
|
||||
var error = function (str) {
|
||||
var tok = "", numTokens = 0, maxTokens = 5;
|
||||
while (numTokens < maxTokens && tokens.length > 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 === "undefined" || tokens[0].value === value) {
|
||||
last_token = tokens.shift();
|
||||
if (type === ID) last_token.value = last_token.value.replace(/^_/, "");
|
||||
return last_token;
|
||||
}
|
||||
};
|
||||
|
||||
var ws = function () {
|
||||
if (!tokens.length) return;
|
||||
if (tokens[0].type === "whitespace") {
|
||||
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: "whitespace", value: "" };
|
||||
while (true) {
|
||||
var w = ws();
|
||||
if (!w) break;
|
||||
t.value += w.value;
|
||||
}
|
||||
if (t.value.length > 0) {
|
||||
if (store) {
|
||||
var w = t.value
|
||||
, re = {
|
||||
"ws": /^([\t\n\r ]+)/
|
||||
, "line-comment": /^\/\/(.*)\n?/m
|
||||
, "multiline-comment": /^\/\*((?:.|\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 < n; i++) {
|
||||
var type = wsTypes[i];
|
||||
w = w.replace(re[type], function (tok, m1) {
|
||||
store.push({ type: type + (pea ? ("-" + pea) : ""), value: m1 });
|
||||
matched = true;
|
||||
return "";
|
||||
});
|
||||
if (matched) break;
|
||||
}
|
||||
if (matched) continue;
|
||||
throw new Error("Surprising white space construct."); // this shouldn't happen
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
var integer_type = function () {
|
||||
var ret = "";
|
||||
all_ws();
|
||||
if (consume(ID, "unsigned")) ret = "unsigned ";
|
||||
all_ws();
|
||||
if (consume(ID, "short")) return ret + "short";
|
||||
if (consume(ID, "long")) {
|
||||
ret += "long";
|
||||
all_ws();
|
||||
if (consume(ID, "long")) return ret + " long";
|
||||
return ret;
|
||||
}
|
||||
if (ret) error("Failed to parse integer type");
|
||||
};
|
||||
|
||||
var float_type = function () {
|
||||
var ret = "";
|
||||
all_ws();
|
||||
if (consume(ID, "unrestricted")) ret = "unrestricted ";
|
||||
all_ws();
|
||||
if (consume(ID, "float")) return ret + "float";
|
||||
if (consume(ID, "double")) return ret + "double";
|
||||
if (ret) error("Failed to parse float type");
|
||||
};
|
||||
|
||||
var primitive_type = function () {
|
||||
var num_type = integer_type() || float_type();
|
||||
if (num_type) return num_type;
|
||||
all_ws();
|
||||
if (consume(ID, "boolean")) return "boolean";
|
||||
if (consume(ID, "byte")) return "byte";
|
||||
if (consume(ID, "octet")) return "octet";
|
||||
};
|
||||
|
||||
var const_value = function () {
|
||||
if (consume(ID, "true")) return { type: "boolean", value: true };
|
||||
if (consume(ID, "false")) return { type: "boolean", value: false };
|
||||
if (consume(ID, "null")) return { type: "null" };
|
||||
if (consume(ID, "Infinity")) return { type: "Infinity", negative: false };
|
||||
if (consume(ID, "NaN")) return { type: "NaN" };
|
||||
var ret = consume(FLOAT) || consume(INT);
|
||||
if (ret) return { type: "number", value: 1 * ret.value };
|
||||
var tok = consume(OTHER, "-");
|
||||
if (tok) {
|
||||
if (consume(ID, "Infinity")) return { type: "Infinity", negative: true };
|
||||
else tokens.unshift(tok);
|
||||
}
|
||||
};
|
||||
|
||||
var type_suffix = function (obj) {
|
||||
while (true) {
|
||||
all_ws();
|
||||
if (consume(OTHER, "?")) {
|
||||
if (obj.nullable) error("Can't nullable more than once");
|
||||
obj.nullable = true;
|
||||
}
|
||||
else if (consume(OTHER, "[")) {
|
||||
all_ws();
|
||||
consume(OTHER, "]") || error("Unterminated array type");
|
||||
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, "<")) {
|
||||
// backwards compat
|
||||
if (value === "sequence") {
|
||||
ret.sequence = true;
|
||||
}
|
||||
ret.generic = value;
|
||||
ret.idlType = type() || error("Error parsing generic type " + value);
|
||||
all_ws();
|
||||
if (!consume(OTHER, ">")) error("Unterminated generic type " + value);
|
||||
all_ws();
|
||||
if (consume(OTHER, "?")) ret.nullable = true;
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
ret.idlType = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
type_suffix(ret);
|
||||
if (ret.nullable && !ret.array && ret.idlType === "any") error("Type any cannot be made nullable");
|
||||
return ret;
|
||||
};
|
||||
|
||||
var union_type = function () {
|
||||
all_ws();
|
||||
if (!consume(OTHER, "(")) return;
|
||||
var ret = { sequence: false, generic: null, nullable: false, array: false, union: true, idlType: [] };
|
||||
var fst = type() || error("Union type with no content");
|
||||
ret.idlType.push(fst);
|
||||
while (true) {
|
||||
all_ws();
|
||||
if (!consume(ID, "or")) break;
|
||||
var typ = type() || error("No type after 'or' in union type");
|
||||
ret.idlType.push(typ);
|
||||
}
|
||||
if (!consume(OTHER, ")")) error("Unterminated union type");
|
||||
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, "pea");
|
||||
var opt_token = consume(ID, "optional");
|
||||
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 >= 3 &&
|
||||
tokens[0].type === "other" && tokens[0].value === "." &&
|
||||
tokens[1].type === "other" && tokens[1].value === "." &&
|
||||
tokens[2].type === "other" && tokens[2].value === "."
|
||||
) {
|
||||
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["default"] = 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, ",")) return ret;
|
||||
var nxt = argument(store ? ret : null) || error("Trailing comma in arguments list");
|
||||
ret.push(nxt);
|
||||
}
|
||||
};
|
||||
|
||||
var type_pair = function () {
|
||||
all_ws();
|
||||
var k = type();
|
||||
if (!k) return;
|
||||
all_ws()
|
||||
if (!consume(OTHER, ",")) 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
|
||||
, "arguments": null
|
||||
};
|
||||
all_ws();
|
||||
var eq = consume(OTHER, "=");
|
||||
if (eq) {
|
||||
all_ws();
|
||||
ret.rhs = consume(ID);
|
||||
if (!ret.rhs) return error("No right hand side to extended attribute assignment");
|
||||
}
|
||||
all_ws();
|
||||
if (consume(OTHER, "(")) {
|
||||
var args, pair;
|
||||
// [Constructor(DOMString str)]
|
||||
if (args = argument_list(store)) {
|
||||
ret["arguments"] = args;
|
||||
}
|
||||
// [MapClass(DOMString, DOMString)]
|
||||
else if (pair = type_pair()) {
|
||||
ret.typePair = pair;
|
||||
}
|
||||
// [Constructor()]
|
||||
else {
|
||||
ret["arguments"] = [];
|
||||
}
|
||||
all_ws();
|
||||
consume(OTHER, ")") || error("Unexpected token in extended attribute argument list or type pair");
|
||||
}
|
||||
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, "[")) return eas;
|
||||
eas[0] = simple_extended_attr(store) || error("Extended attribute with not content");
|
||||
all_ws();
|
||||
while (consume(OTHER, ",")) {
|
||||
eas.push(simple_extended_attr(store) || error("Trailing comma in extended attribute"));
|
||||
all_ws();
|
||||
}
|
||||
consume(OTHER, "]") || error("No end of extended attribute");
|
||||
return eas;
|
||||
};
|
||||
|
||||
var default_ = function () {
|
||||
all_ws();
|
||||
if (consume(OTHER, "=")) {
|
||||
all_ws();
|
||||
var def = const_value();
|
||||
if (def) {
|
||||
return def;
|
||||
}
|
||||
else {
|
||||
var str = consume(STR) || error("No value for default");
|
||||
str.value = str.value.replace(/^"/, "").replace(/"$/, "");
|
||||
return str;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var const_ = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "const")) return;
|
||||
var ret = { type: "const", nullable: false };
|
||||
all_ws();
|
||||
var typ = primitive_type();
|
||||
if (!typ) {
|
||||
typ = consume(ID) || error("No type for const");
|
||||
typ = typ.value;
|
||||
}
|
||||
ret.idlType = typ;
|
||||
all_ws();
|
||||
if (consume(OTHER, "?")) {
|
||||
ret.nullable = true;
|
||||
all_ws();
|
||||
}
|
||||
var name = consume(ID) || error("No name for const");
|
||||
ret.name = name.value;
|
||||
all_ws();
|
||||
consume(OTHER, "=") || error("No value assignment for const");
|
||||
all_ws();
|
||||
var cnt = const_value();
|
||||
if (cnt) ret.value = cnt;
|
||||
else error("No value for const");
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Unterminated const");
|
||||
return ret;
|
||||
};
|
||||
|
||||
var inheritance = function () {
|
||||
all_ws();
|
||||
if (consume(OTHER, ":")) {
|
||||
all_ws();
|
||||
var inh = consume(ID) || error ("No type in inheritance");
|
||||
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, "(") || error("Invalid operation");
|
||||
ret["arguments"] = argument_list(store) || [];
|
||||
all_ws();
|
||||
consume(OTHER, ")") || error("Unterminated operation");
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Unterminated operation");
|
||||
return ret;
|
||||
};
|
||||
|
||||
var callback = function (store) {
|
||||
all_ws(store, "pea");
|
||||
var ret;
|
||||
if (!consume(ID, "callback")) return;
|
||||
all_ws();
|
||||
var tok = consume(ID, "interface");
|
||||
if (tok) {
|
||||
tokens.unshift(tok);
|
||||
ret = interface_();
|
||||
ret.type = "callback interface";
|
||||
return ret;
|
||||
}
|
||||
var name = consume(ID) || error("No name for callback");
|
||||
ret = { type: "callback", name: name.value };
|
||||
all_ws();
|
||||
consume(OTHER, "=") || error("No assignment in callback");
|
||||
all_ws();
|
||||
ret.idlType = return_type();
|
||||
all_ws();
|
||||
consume(OTHER, "(") || error("No arguments in callback");
|
||||
ret["arguments"] = argument_list(store) || [];
|
||||
all_ws();
|
||||
consume(OTHER, ")") || error("Unterminated callback");
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Unterminated callback");
|
||||
return ret;
|
||||
};
|
||||
|
||||
var attribute = function (store) {
|
||||
all_ws(store, "pea");
|
||||
var grabbed = []
|
||||
, ret = {
|
||||
type: "attribute"
|
||||
, "static": false
|
||||
, stringifier: false
|
||||
, inherit: false
|
||||
, readonly: false
|
||||
};
|
||||
if (consume(ID, "static")) {
|
||||
ret["static"] = true;
|
||||
grabbed.push(last_token);
|
||||
}
|
||||
else if (consume(ID, "stringifier")) {
|
||||
ret.stringifier = true;
|
||||
grabbed.push(last_token);
|
||||
}
|
||||
var w = all_ws();
|
||||
if (w) grabbed.push(w);
|
||||
if (consume(ID, "inherit")) {
|
||||
if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit");
|
||||
ret.inherit = true;
|
||||
grabbed.push(last_token);
|
||||
var w = all_ws();
|
||||
if (w) grabbed.push(w);
|
||||
}
|
||||
if (consume(ID, "readonly")) {
|
||||
ret.readonly = true;
|
||||
grabbed.push(last_token);
|
||||
var w = all_ws();
|
||||
if (w) grabbed.push(w);
|
||||
}
|
||||
if (!consume(ID, "attribute")) {
|
||||
tokens = grabbed.concat(tokens);
|
||||
return;
|
||||
}
|
||||
all_ws();
|
||||
ret.idlType = type() || error("No type in attribute");
|
||||
if (ret.idlType.sequence) error("Attributes cannot accept sequence types");
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name in attribute");
|
||||
ret.name = name.value;
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Unterminated attribute");
|
||||
return ret;
|
||||
};
|
||||
|
||||
var return_type = function () {
|
||||
var typ = type();
|
||||
if (!typ) {
|
||||
if (consume(ID, "void")) {
|
||||
return "void";
|
||||
}
|
||||
else error("No return type");
|
||||
}
|
||||
return typ;
|
||||
};
|
||||
|
||||
var operation = function (store) {
|
||||
all_ws(store, "pea");
|
||||
var ret = {
|
||||
type: "operation"
|
||||
, getter: false
|
||||
, setter: false
|
||||
, creator: false
|
||||
, deleter: false
|
||||
, legacycaller: false
|
||||
, "static": false
|
||||
, stringifier: false
|
||||
};
|
||||
while (true) {
|
||||
all_ws();
|
||||
if (consume(ID, "getter")) ret.getter = true;
|
||||
else if (consume(ID, "setter")) ret.setter = true;
|
||||
else if (consume(ID, "creator")) ret.creator = true;
|
||||
else if (consume(ID, "deleter")) ret.deleter = true;
|
||||
else if (consume(ID, "legacycaller")) 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, "static")) {
|
||||
ret["static"] = true;
|
||||
ret.idlType = return_type();
|
||||
operation_rest(ret, store);
|
||||
return ret;
|
||||
}
|
||||
else if (consume(ID, "stringifier")) {
|
||||
ret.stringifier = true;
|
||||
all_ws();
|
||||
if (consume(OTHER, ";")) return ret;
|
||||
ret.idlType = return_type();
|
||||
operation_rest(ret, store);
|
||||
return ret;
|
||||
}
|
||||
ret.idlType = return_type();
|
||||
all_ws();
|
||||
if (consume(ID, "iterator")) {
|
||||
all_ws();
|
||||
ret.type = "iterator";
|
||||
if (consume(ID, "object")) {
|
||||
ret.iteratorObject = "object";
|
||||
}
|
||||
else if (consume(OTHER, "=")) {
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No right hand side in iterator");
|
||||
ret.iteratorObject = name.value;
|
||||
}
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Unterminated iterator");
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
operation_rest(ret, store);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
var identifiers = function (arr) {
|
||||
while (true) {
|
||||
all_ws();
|
||||
if (consume(OTHER, ",")) {
|
||||
all_ws();
|
||||
var name = consume(ID) || error("Trailing comma in identifiers list");
|
||||
arr.push(name.value);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
};
|
||||
|
||||
var serialiser = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "serializer")) return;
|
||||
var ret = { type: "serializer" };
|
||||
all_ws();
|
||||
if (consume(OTHER, "=")) {
|
||||
all_ws();
|
||||
if (consume(OTHER, "{")) {
|
||||
ret.patternMap = true;
|
||||
all_ws();
|
||||
var id = consume(ID);
|
||||
if (id && id.value === "getter") {
|
||||
ret.names = ["getter"];
|
||||
}
|
||||
else if (id && id.value === "inherit") {
|
||||
ret.names = ["inherit"];
|
||||
identifiers(ret.names);
|
||||
}
|
||||
else if (id) {
|
||||
ret.names = [id.value];
|
||||
identifiers(ret.names);
|
||||
}
|
||||
else {
|
||||
ret.names = [];
|
||||
}
|
||||
all_ws();
|
||||
consume(OTHER, "}") || error("Unterminated serializer pattern map");
|
||||
}
|
||||
else if (consume(OTHER, "[")) {
|
||||
ret.patternList = true;
|
||||
all_ws();
|
||||
var id = consume(ID);
|
||||
if (id && id.value === "getter") {
|
||||
ret.names = ["getter"];
|
||||
}
|
||||
else if (id) {
|
||||
ret.names = [id.value];
|
||||
identifiers(ret.names);
|
||||
}
|
||||
else {
|
||||
ret.names = [];
|
||||
}
|
||||
all_ws();
|
||||
consume(OTHER, "]") || error("Unterminated serializer pattern list");
|
||||
}
|
||||
else {
|
||||
var name = consume(ID) || error("Invalid serializer");
|
||||
ret.name = name.value;
|
||||
}
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Unterminated serializer");
|
||||
return ret;
|
||||
}
|
||||
else if (consume(OTHER, ";")) {
|
||||
// noop, just parsing
|
||||
}
|
||||
else {
|
||||
ret.idlType = return_type();
|
||||
all_ws();
|
||||
ret.operation = operation_rest(null, store);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
var interface_ = function (isPartial, store) {
|
||||
all_ws(isPartial ? null : store, "pea");
|
||||
if (!consume(ID, "interface")) return;
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name for interface");
|
||||
var mems = []
|
||||
, ret = {
|
||||
type: "interface"
|
||||
, name: name.value
|
||||
, partial: false
|
||||
, members: mems
|
||||
};
|
||||
if (!isPartial) ret.inheritance = inheritance() || null;
|
||||
all_ws();
|
||||
consume(OTHER, "{") || error("Bodyless interface");
|
||||
while (true) {
|
||||
all_ws(store ? mems : null);
|
||||
if (consume(OTHER, "}")) {
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Missing semicolon after interface");
|
||||
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 = serialiser(store ? mems : null) ||
|
||||
attribute(store ? mems : null) ||
|
||||
operation(store ? mems : null) ||
|
||||
error("Unknown member");
|
||||
mem.extAttrs = ea;
|
||||
ret.members.push(mem);
|
||||
}
|
||||
};
|
||||
|
||||
var partial = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "partial")) return;
|
||||
var thing = dictionary(true, store) ||
|
||||
interface_(true, store) ||
|
||||
error("Partial doesn't apply to anything");
|
||||
thing.partial = true;
|
||||
return thing;
|
||||
};
|
||||
|
||||
var dictionary = function (isPartial, store) {
|
||||
all_ws(isPartial ? null : store, "pea");
|
||||
if (!consume(ID, "dictionary")) return;
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name for dictionary");
|
||||
var mems = []
|
||||
, ret = {
|
||||
type: "dictionary"
|
||||
, name: name.value
|
||||
, partial: false
|
||||
, members: mems
|
||||
};
|
||||
if (!isPartial) ret.inheritance = inheritance() || null;
|
||||
all_ws();
|
||||
consume(OTHER, "{") || error("Bodyless dictionary");
|
||||
while (true) {
|
||||
all_ws(store ? mems : null);
|
||||
if (consume(OTHER, "}")) {
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Missing semicolon after dictionary");
|
||||
return ret;
|
||||
}
|
||||
var ea = extended_attrs(store ? mems : null);
|
||||
all_ws(store ? mems : null, "pea");
|
||||
var typ = type() || error("No type for dictionary member");
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name for dictionary member");
|
||||
ret.members.push({
|
||||
type: "field"
|
||||
, name: name.value
|
||||
, idlType: typ
|
||||
, extAttrs: ea
|
||||
, "default": default_()
|
||||
});
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Unterminated dictionary member");
|
||||
}
|
||||
};
|
||||
|
||||
var exception = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "exception")) return;
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name for exception");
|
||||
var mems = []
|
||||
, ret = {
|
||||
type: "exception"
|
||||
, name: name.value
|
||||
, members: mems
|
||||
};
|
||||
ret.inheritance = inheritance() || null;
|
||||
all_ws();
|
||||
consume(OTHER, "{") || error("Bodyless exception");
|
||||
while (true) {
|
||||
all_ws(store ? mems : null);
|
||||
if (consume(OTHER, "}")) {
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Missing semicolon after exception");
|
||||
return ret;
|
||||
}
|
||||
var ea = extended_attrs(store ? mems : null);
|
||||
all_ws(store ? mems : null, "pea");
|
||||
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, ";")) error("Unknown member in exception body");
|
||||
ret.members.push({
|
||||
type: "field"
|
||||
, name: name.value
|
||||
, idlType: typ
|
||||
, extAttrs: ea
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var enum_ = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "enum")) return;
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name for enum");
|
||||
var vals = []
|
||||
, ret = {
|
||||
type: "enum"
|
||||
, name: name.value
|
||||
, values: vals
|
||||
};
|
||||
all_ws();
|
||||
consume(OTHER, "{") || error("No curly for enum");
|
||||
var saw_comma = false;
|
||||
while (true) {
|
||||
all_ws(store ? vals : null);
|
||||
if (consume(OTHER, "}")) {
|
||||
all_ws();
|
||||
if (saw_comma) error("Trailing comma in enum");
|
||||
consume(OTHER, ";") || error("No semicolon after enum");
|
||||
return ret;
|
||||
}
|
||||
var val = consume(STR) || error("Unexpected value in enum");
|
||||
ret.values.push(val.value.replace(/"/g, ""));
|
||||
all_ws(store ? vals : null);
|
||||
if (consume(OTHER, ",")) {
|
||||
if (store) vals.push({ type: "," });
|
||||
all_ws(store ? vals : null);
|
||||
saw_comma = true;
|
||||
}
|
||||
else {
|
||||
saw_comma = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var typedef = function (store) {
|
||||
all_ws(store, "pea");
|
||||
if (!consume(ID, "typedef")) return;
|
||||
var ret = {
|
||||
type: "typedef"
|
||||
};
|
||||
all_ws();
|
||||
ret.typeExtAttrs = extended_attrs();
|
||||
all_ws(store, "tpea");
|
||||
ret.idlType = type() || error("No type in typedef");
|
||||
all_ws();
|
||||
var name = consume(ID) || error("No name in typedef");
|
||||
ret.name = name.value;
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("Unterminated typedef");
|
||||
return ret;
|
||||
};
|
||||
|
||||
var implements_ = function (store) {
|
||||
all_ws(store, "pea");
|
||||
var target = consume(ID);
|
||||
if (!target) return;
|
||||
var w = all_ws();
|
||||
if (consume(ID, "implements")) {
|
||||
var ret = {
|
||||
type: "implements"
|
||||
, target: target.value
|
||||
};
|
||||
all_ws();
|
||||
var imp = consume(ID) || error("Incomplete implements statement");
|
||||
ret["implements"] = imp.value;
|
||||
all_ws();
|
||||
consume(OTHER, ";") || error("No terminating ; for implements statement");
|
||||
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("Stray extended attributes");
|
||||
break;
|
||||
}
|
||||
def.extAttrs = ea;
|
||||
defs.push(def);
|
||||
}
|
||||
return defs;
|
||||
};
|
||||
var res = definitions(opt.ws);
|
||||
if (tokens.length) error("Unrecognised tokens");
|
||||
return res;
|
||||
};
|
||||
|
||||
var inNode = typeof module !== "undefined" && 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;
|
||||
}());
|
236
tests/wpt/web-platform-tests/resources/webidl2/lib/writer.js
Normal file
236
tests/wpt/web-platform-tests/resources/webidl2/lib/writer.js
Normal file
|
@ -0,0 +1,236 @@
|
|||
|
||||
(function () {
|
||||
|
||||
var write = function (ast, opt) {
|
||||
var curPea = ""
|
||||
, curTPea = ""
|
||||
, opt = opt || {}
|
||||
, noop = function (str) { return str; }
|
||||
, optNames = "type".split(" ")
|
||||
, context = []
|
||||
;
|
||||
for (var i = 0, n = optNames.length; i < n; i++) {
|
||||
var o = optNames[i];
|
||||
if (!opt[o]) opt[o] = noop;
|
||||
}
|
||||
|
||||
var literal = function (it) {
|
||||
return it.value;
|
||||
};
|
||||
var wsPea = function (it) {
|
||||
curPea += it.value;
|
||||
return "";
|
||||
};
|
||||
var wsTPea = function (it) {
|
||||
curTPea += it.value;
|
||||
return "";
|
||||
};
|
||||
var lineComment = function (it) {
|
||||
return "//" + it.value + "\n";
|
||||
};
|
||||
var multilineComment = function (it) {
|
||||
return "/*" + it.value + "*/";
|
||||
};
|
||||
var type = function (it) {
|
||||
if (typeof it === "string") return opt.type(it); // XXX should maintain some context
|
||||
if (it.union) return "(" + it.idlType.map(type).join(" or ") + ")";
|
||||
var ret = "";
|
||||
if (it.sequence) ret += "sequence<";
|
||||
ret += type(it.idlType);
|
||||
if (it.array) {
|
||||
for (var i = 0, n = it.nullableArray.length; i < n; i++) {
|
||||
var val = it.nullableArray[i];
|
||||
if (val) ret += "?";
|
||||
ret += "[]";
|
||||
}
|
||||
}
|
||||
if (it.sequence) ret += ">";
|
||||
if (it.nullable) ret += "?";
|
||||
|
||||
return ret;
|
||||
};
|
||||
var const_value = function (it) {
|
||||
var tp = it. type;
|
||||
if (tp === "boolean") return it.value ? "true" : "false";
|
||||
else if (tp === "null") return "null";
|
||||
else if (tp === "Infinity") return (it.negative ? "-" : "") + "Infinity";
|
||||
else if (tp === "NaN") return "NaN";
|
||||
else if (tp === "number") return it.value;
|
||||
else return '"' + it.value + '"';
|
||||
};
|
||||
var argument = function (arg, pea) {
|
||||
var ret = extended_attributes(arg.extAttrs, pea);
|
||||
if (arg.optional) ret += "optional ";
|
||||
ret += type(arg.idlType);
|
||||
if (arg.variadic) ret += "...";
|
||||
ret += " " + arg.name;
|
||||
if (arg["default"]) ret += " = " + const_value(arg["default"]);
|
||||
return ret;
|
||||
};
|
||||
var args = function (its) {
|
||||
var res = ""
|
||||
, pea = ""
|
||||
;
|
||||
for (var i = 0, n = its.length; i < n; i++) {
|
||||
var arg = its[i];
|
||||
if (arg.type === "ws") res += arg.value;
|
||||
else if (arg.type === "ws-pea") pea += arg.value;
|
||||
else {
|
||||
res += argument(arg, pea);
|
||||
if (i < n - 1) res += ",";
|
||||
pea = "";
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
var make_ext_at = function (it) {
|
||||
if (it["arguments"] === null) return it.name;
|
||||
context.unshift(it);
|
||||
var ret = it.name + "(" + (it["arguments"].length ? args(it["arguments"]) : "") + ")";
|
||||
context.shift(); // XXX need to add more contexts, but not more than needed for ReSpec
|
||||
return ret;
|
||||
};
|
||||
var extended_attributes = function (eats, pea) {
|
||||
if (!eats || !eats.length) return "";
|
||||
return "[" + eats.map(make_ext_at).join(", ") + "]" + pea;
|
||||
};
|
||||
|
||||
var modifiers = "getter setter creator deleter legacycaller stringifier static".split(" ");
|
||||
var operation = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
if (it.stringifier && !it.idlType) return "stringifier;";
|
||||
for (var i = 0, n = modifiers.length; i < n; i++) {
|
||||
var mod = modifiers[i];
|
||||
if (it[mod]) ret += mod + " ";
|
||||
}
|
||||
ret += type(it.idlType) + " ";
|
||||
if (it.name) ret += it.name;
|
||||
ret += "(" + args(it["arguments"]) + ");";
|
||||
return ret;
|
||||
};
|
||||
|
||||
var attribute = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
if (it["static"]) ret += "static ";
|
||||
if (it.stringifier) ret += "stringifier ";
|
||||
if (it.readonly) ret += "readonly ";
|
||||
if (it.inherit) ret += "inherit ";
|
||||
ret += "attribute " + type(it.idlType) + " " + it.name + ";";
|
||||
return ret;
|
||||
};
|
||||
|
||||
var interface_ = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
if (it.partial) ret += "partial ";
|
||||
ret += "interface " + it.name + " ";
|
||||
if (it.inheritance) ret += ": " + it.inheritance + " ";
|
||||
ret += "{" + iterate(it.members) + "};";
|
||||
return ret;
|
||||
};
|
||||
|
||||
var dictionary = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
if (it.partial) ret += "partial ";
|
||||
ret += "dictionary " + it.name + " ";
|
||||
ret += "{" + iterate(it.members) + "};";
|
||||
return ret;
|
||||
};
|
||||
var field = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
ret += type(it.idlType) + " " + it.name;
|
||||
if (it["default"]) ret += " = " + const_value(it["default"]);
|
||||
ret += ";";
|
||||
return ret;
|
||||
};
|
||||
var exception = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
ret += "exception " + it.name + " ";
|
||||
if (it.inheritance) ret += ": " + it.inheritance + " ";
|
||||
ret += "{" + iterate(it.members) + "};";
|
||||
return ret;
|
||||
};
|
||||
var const_ = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
return ret + "const " + type(it.idlType) + " " + it.name + " = " + const_value(it.value) + ";";
|
||||
};
|
||||
var typedef = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
ret += "typedef " + extended_attributes(it.typeExtAttrs, curTPea);
|
||||
curTPea = "";
|
||||
return ret + type(it.idlType) + " " + it.name + ";";
|
||||
};
|
||||
var implements_ = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
return ret + it.target + " implements " + it["implements"] + ";";
|
||||
};
|
||||
var callback = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
return ret + "callback " + it.name + " = " + type(it.idlType) +
|
||||
"(" + args(it["arguments"]) + ");";
|
||||
};
|
||||
var enum_ = function (it) {
|
||||
var ret = extended_attributes(it.extAttrs, curPea);
|
||||
curPea = "";
|
||||
ret += "enum " + it.name + " {";
|
||||
for (var i = 0, n = it.values.length; i < n; i++) {
|
||||
var v = it.values[i];
|
||||
if (typeof v === "string") ret += '"' + v + '"';
|
||||
else if (v.type === "ws") ret += v.value;
|
||||
else if (v.type === ",") ret += ",";
|
||||
}
|
||||
return ret + "};";
|
||||
};
|
||||
|
||||
var table = {
|
||||
ws: literal
|
||||
, "ws-pea": wsPea
|
||||
, "ws-tpea": wsTPea
|
||||
, "line-comment": lineComment
|
||||
, "multiline-comment": multilineComment
|
||||
, "interface": interface_
|
||||
, operation: operation
|
||||
, attribute: attribute
|
||||
, dictionary: dictionary
|
||||
, field: field
|
||||
, exception: exception
|
||||
, "const": const_
|
||||
, typedef: typedef
|
||||
, "implements": implements_
|
||||
, callback: callback
|
||||
, "enum": enum_
|
||||
};
|
||||
var dispatch = function (it) {
|
||||
return table[it.type](it);
|
||||
};
|
||||
var iterate = function (things) {
|
||||
if (!things) return;
|
||||
var ret = "";
|
||||
for (var i = 0, n = things.length; i < n; i++) ret += dispatch(things[i]);
|
||||
return ret;
|
||||
};
|
||||
return iterate(ast);
|
||||
};
|
||||
|
||||
|
||||
var inNode = typeof module !== "undefined" && module.exports
|
||||
, obj = {
|
||||
write: function (ast, opt) {
|
||||
if (!opt) opt = {};
|
||||
return write(ast, opt);
|
||||
}
|
||||
};
|
||||
|
||||
if (inNode) module.exports = obj;
|
||||
else window.WebIDL2Writer = obj;
|
||||
|
||||
}());
|
22
tests/wpt/web-platform-tests/resources/webidl2/package.json
Normal file
22
tests/wpt/web-platform-tests/resources/webidl2/package.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "webidl2"
|
||||
, "description": "A WebIDL Parser"
|
||||
, "version": "2.0.4"
|
||||
, "author": "Robin Berjon <robin@berjon.com>"
|
||||
, "license": "MIT"
|
||||
, "dependencies": {
|
||||
}
|
||||
, "devDependencies": {
|
||||
"mocha": "1.7.4"
|
||||
, "expect.js": "0.2.0"
|
||||
, "underscore": "1.4.3"
|
||||
, "jsondiffpatch": "0.0.5"
|
||||
, "benchmark": "*"
|
||||
, "microtime": "*"
|
||||
}
|
||||
, "scripts": {
|
||||
"test": "mocha"
|
||||
}
|
||||
, "repository": "git://github.com/darobin/webidl2.js"
|
||||
, "main": "index"
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
// NOTES:
|
||||
// - the errors actually still need to be reviewed to check that they
|
||||
// are fully correct interpretations of the IDLs
|
||||
|
||||
var wp = process.env.JSCOV ? require("../lib-cov/webidl2") : require("../lib/webidl2")
|
||||
, expect = require("expect.js")
|
||||
, pth = require("path")
|
||||
, fs = require("fs")
|
||||
;
|
||||
describe("Parses all of the invalid IDLs to check that they blow up correctly", function () {
|
||||
var dir = pth.join(__dirname, "invalid/idl")
|
||||
, skip = {}
|
||||
, idls = fs.readdirSync(dir)
|
||||
.filter(function (it) { return (/\.w?idl$/).test(it) && !skip[it]; })
|
||||
.map(function (it) { return pth.join(dir, it); })
|
||||
, errors = idls.map(function (it) { return pth.join(__dirname, "invalid", "json", pth.basename(it).replace(/\.w?idl/, ".json")); })
|
||||
;
|
||||
|
||||
for (var i = 0, n = idls.length; i < n; i++) {
|
||||
var idl = idls[i], error = JSON.parse(fs.readFileSync(errors[i], "utf8"));
|
||||
var func = (function (idl, err) {
|
||||
return function () {
|
||||
var error;
|
||||
try {
|
||||
var ast = wp.parse(fs.readFileSync(idl, "utf8"));
|
||||
console.log(JSON.stringify(ast, null, 4));
|
||||
}
|
||||
catch (e) {
|
||||
error = e;
|
||||
}
|
||||
finally {
|
||||
expect(error).to.be.ok();
|
||||
expect(error.message).to.equal(err.message);
|
||||
expect(error.line).to.equal(err.line);
|
||||
}
|
||||
|
||||
};
|
||||
}(idl, error));
|
||||
it("should produce the right error for " + idl, func);
|
||||
}
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
enum foo { 1, 2, 3};
|
|
@ -0,0 +1,25 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
module gfx {
|
||||
|
||||
module geom {
|
||||
interface Shape { /* ... */ };
|
||||
interface Rectangle : Shape { /* ... */ };
|
||||
interface Path : Shape { /* ... */ };
|
||||
};
|
||||
|
||||
interface GraphicsContext {
|
||||
void fillShape(geom::Shape s);
|
||||
void strokeShape(geom::Shape s);
|
||||
};
|
||||
};
|
||||
|
||||
module gui {
|
||||
|
||||
interface Widget { /* ... */ };
|
||||
|
||||
interface Window : Widget {
|
||||
gfx::GraphicsContext getGraphicsContext();
|
||||
};
|
||||
|
||||
interface Button : Widget { /* ... */ };
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
interface NonNullable {
|
||||
attribute any? foo;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
interface Foo {};
|
||||
|
||||
interface NonNullable {
|
||||
attribute Foo?? foo;
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
// getraises and setraises are not longer valid Web IDL
|
||||
interface Person {
|
||||
|
||||
// An attribute that can raise an exception if it is set to an invalid value.
|
||||
attribute DOMString name setraises (InvalidName);
|
||||
|
||||
// An attribute whose value cannot be assigned to, and which can raise an
|
||||
// exception some circumstances.
|
||||
readonly attribute DOMString petName getraises (NoSuchPet);
|
||||
};
|
||||
|
||||
exception SomeException {
|
||||
};
|
||||
|
||||
interface ExceptionThrower {
|
||||
// This attribute always throws a SomeException and never returns a value.
|
||||
attribute long valueOf getraises(SomeException);
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
// scoped names are no longer valid in WebIDL
|
||||
typedef gfx::geom::geom2d::Point Point;
|
|
@ -0,0 +1,3 @@
|
|||
interface sequenceAsAttribute {
|
||||
attribute sequence<short> invalid;
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
// omittable is no longer a recognized keywoard as of 20110905
|
||||
interface Dictionary {
|
||||
readonly attribute unsigned long propertyCount;
|
||||
|
||||
omittable getter float getProperty(DOMString propertyName);
|
||||
omittable setter void setProperty(DOMString propertyName, float propertyValue);
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
interface Util {
|
||||
const DOMString hello = "world";
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "Unexpected value in enum"
|
||||
, "line": 1
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "Unrecognised tokens"
|
||||
, "line": 2
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "Type any cannot be made nullable"
|
||||
, "line": 2
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "Can't nullable more than once"
|
||||
, "line": 4
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "Unterminated attribute"
|
||||
, "line": 5
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "No name in typedef"
|
||||
, "line": 2
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "Attributes cannot accept sequence types"
|
||||
, "line": 2
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "Invalid operation"
|
||||
, "line": 6
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"message": "No value for const"
|
||||
, "line": 2
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
--reporter spec
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
var wp = process.env.JSCOV ? require("../lib-cov/webidl2") : require("../lib/webidl2")
|
||||
, expect = require("expect.js")
|
||||
, pth = require("path")
|
||||
, fs = require("fs")
|
||||
, jdp = require("jsondiffpatch")
|
||||
, debug = true
|
||||
;
|
||||
describe("Parses all of the IDLs to produce the correct ASTs", function () {
|
||||
var dir = pth.join(__dirname, "syntax/idl")
|
||||
, skip = {} // use if we have a broken test
|
||||
, idls = fs.readdirSync(dir)
|
||||
.filter(function (it) { return (/\.widl$/).test(it) && !skip[it]; })
|
||||
.map(function (it) { return pth.join(dir, it); })
|
||||
, jsons = idls.map(function (it) { return pth.join(__dirname, "syntax/json", pth.basename(it).replace(".widl", ".json")); })
|
||||
;
|
||||
|
||||
for (var i = 0, n = idls.length; i < n; i++) {
|
||||
var idl = idls[i], json = jsons[i];
|
||||
var func = (function (idl, json) {
|
||||
return function () {
|
||||
try {
|
||||
var diff = jdp.diff(JSON.parse(fs.readFileSync(json, "utf8")),
|
||||
wp.parse(fs.readFileSync(idl, "utf8")));
|
||||
if (diff && debug) console.log(JSON.stringify(diff, null, 4));
|
||||
expect(diff).to.be(undefined);
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e.toString());
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
}(idl, json));
|
||||
it("should produce the same AST for " + idl, func);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface B {
|
||||
void g();
|
||||
void g(B b);
|
||||
void g([AllowAny] DOMString s);
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
[Constructor]
|
||||
interface LotteryResults {
|
||||
readonly attribute unsigned short[][] numbers;
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
exception InvalidName {
|
||||
DOMString reason;
|
||||
};
|
||||
|
||||
exception NoSuchPet { };
|
||||
|
||||
interface Person {
|
||||
|
||||
// A simple attribute that can be set to any value the range an unsigned
|
||||
// short can take.
|
||||
attribute unsigned short age;
|
||||
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
callback AsyncOperationCallback = void (DOMString status);
|
||||
|
||||
callback interface EventHandler {
|
||||
void eventOccurred(DOMString details);
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface NumberQuadrupler {
|
||||
// This operation simply returns four times the given number x.
|
||||
legacycaller float compute(float x);
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Util {
|
||||
const boolean DEBUG = false;
|
||||
const short negative = -1;
|
||||
const octet LF = 10;
|
||||
const unsigned long BIT_MASK = 0x0000fc00;
|
||||
const float AVOGADRO = 6.022e23;
|
||||
const unrestricted float sobig = Infinity;
|
||||
const unrestricted double minusonedividedbyzero = -Infinity;
|
||||
const short notanumber = NaN;
|
||||
};
|
||||
|
||||
exception Error {
|
||||
const short ERR_UNKNOWN = 0;
|
||||
const short ERR_OUT_OF_MEMORY = 1;
|
||||
|
||||
short errorCode;
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
[Constructor,
|
||||
Constructor(float radius)]
|
||||
interface Circle {
|
||||
attribute float r;
|
||||
attribute float cx;
|
||||
attribute float cy;
|
||||
readonly attribute float circumference;
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
dictionary PaintOptions {
|
||||
DOMString? fillPattern = "black";
|
||||
DOMString? strokePattern = null;
|
||||
Point position;
|
||||
};
|
||||
|
||||
dictionary WetPaintOptions : PaintOptions {
|
||||
float hydrometry;
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
// Extracted from Web IDL editors draft May 31 2011
|
||||
dictionary PaintOptions {
|
||||
DOMString? fillPattern = "black";
|
||||
DOMString? strokePattern = null;
|
||||
Point position;
|
||||
};
|
||||
|
||||
partial dictionary A {
|
||||
long h;
|
||||
long d;
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* \brief Testing documentation features
|
||||
*
|
||||
* This is a
|
||||
* single paragraph
|
||||
*
|
||||
* <p>This is valid.</p>
|
||||
* <p>This is <em>valid</em>.</p>
|
||||
* <p>This is <b>valid</b>.</p>
|
||||
* <p>This is <a href=''>valid</a>.</p>
|
||||
* <ul>
|
||||
* <li>This</li>
|
||||
* <li>is</li>
|
||||
* <li>valid</li>
|
||||
* </ul>
|
||||
* <dl>
|
||||
* <dt>This</dt>
|
||||
* <dd>valid</dd>
|
||||
* </dl>
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td>this</td>
|
||||
* <td>is</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>valid</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>This is <br> valid.</p>
|
||||
* <p>This is <br /> valid.</p>
|
||||
* <p>This is <br/> valid.</p>
|
||||
*/
|
||||
interface Documentation {};
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* \brief Testing documentation features
|
||||
*
|
||||
* This is a
|
||||
* single paragraph
|
||||
*
|
||||
* <p>This is valid.</p>
|
||||
* <p>This is <em>valid</em>.</p>
|
||||
* <p>This is <b>valid</b>.</p>
|
||||
* <p>This is <a href=''>valid</a>.</p>
|
||||
* <ul>
|
||||
* <li>This</li>
|
||||
* <li>is</li>
|
||||
* <li>valid</li>
|
||||
* </ul>
|
||||
* <dl>
|
||||
* <dt>This</dt>
|
||||
* <dd>valid</dd>
|
||||
* </dl>
|
||||
* <table>
|
||||
* <tr>
|
||||
* <td>this</td>
|
||||
* <td>is</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>valid</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>This is <br> valid.</p>
|
||||
* <p>This is <br /> valid.</p>
|
||||
* <p>This is <br/> valid.</p>
|
||||
* <p><img src="foo.png" alt="Valid"/></p>
|
||||
*/
|
||||
interface Documentation {};
|
|
@ -0,0 +1,8 @@
|
|||
enum MealType { "rice", "noodles", "other" };
|
||||
|
||||
interface Meal {
|
||||
attribute MealType type;
|
||||
attribute float size; // in grams
|
||||
|
||||
void initialize(MealType type, float size);
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Dictionary {
|
||||
readonly attribute unsigned long propertyCount;
|
||||
|
||||
getter float getProperty(DOMString propertyName);
|
||||
setter void setProperty(DOMString propertyName, float propertyValue);
|
||||
};
|
||||
|
||||
|
||||
interface Dictionary {
|
||||
readonly attribute unsigned long propertyCount;
|
||||
|
||||
float getProperty(DOMString propertyName);
|
||||
void setProperty(DOMString propertyName, float propertyValue);
|
||||
|
||||
getter float (DOMString propertyName);
|
||||
setter void (DOMString propertyName, float propertyValue);
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
// from http://lists.w3.org/Archives/Public/public-script-coord/2010OctDec/0112.html
|
||||
exception DOMException {
|
||||
unsigned short code;
|
||||
};
|
||||
|
||||
exception HierarchyRequestError : DOMException { };
|
||||
exception NoModificationAllowedError : DOMException { };
|
|
@ -0,0 +1,8 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Dahut {
|
||||
attribute DOMString type;
|
||||
};
|
||||
|
||||
exception SomeException {
|
||||
};
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
interface Foo {
|
||||
Promise<ResponsePromise<sequence<DOMString?>>> bar();
|
||||
};
|
||||
|
||||
// Extracted from https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ on 2014-05-08
|
||||
|
||||
interface ServiceWorkerClients {
|
||||
Promise<Client[]?> getServiced();
|
||||
Promise<any> reloadAll();
|
||||
};
|
||||
|
||||
// Extracted from https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ on 2014-05-13
|
||||
|
||||
interface FetchEvent : Event {
|
||||
ResponsePromise<any> default();
|
||||
};
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Dictionary {
|
||||
readonly attribute unsigned long propertyCount;
|
||||
|
||||
getter float (DOMString propertyName);
|
||||
setter void (DOMString propertyName, float propertyValue);
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
// Typedef identifier: "number"
|
||||
// Qualified name: "::framework::number"
|
||||
typedef float number;
|
||||
|
||||
// Exception identifier: "FrameworkException"
|
||||
// Qualified name: "::framework::FrameworkException"
|
||||
exception FrameworkException {
|
||||
|
||||
// Constant identifier: "ERR_NOT_FOUND"
|
||||
// Qualified name: "::framework::FrameworkException::ERR_NOT_FOUND"
|
||||
const long ERR_NOT_FOUND = 1;
|
||||
|
||||
// Exception field identifier: "code"
|
||||
long code;
|
||||
};
|
||||
|
||||
// Interface identifier: "System"
|
||||
// Qualified name: "::framework::System"
|
||||
interface System {
|
||||
|
||||
// Operation identifier: "createObject"
|
||||
// Operation argument identifier: "interface"
|
||||
object createObject(DOMString _interface);
|
||||
|
||||
// Operation has no identifier; it declares a getter.
|
||||
getter DOMString (DOMString keyName);
|
||||
};
|
||||
|
||||
|
||||
// Interface identifier: "TextField"
|
||||
// Qualified name: "::framework::gui::TextField"
|
||||
interface TextField {
|
||||
|
||||
// Attribute identifier: "const"
|
||||
attribute boolean _const;
|
||||
|
||||
// Attribute identifier: "value"
|
||||
attribute DOMString? _value;
|
||||
};
|
||||
|
||||
interface Foo {
|
||||
void op(object interface);
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Node {
|
||||
readonly attribute unsigned short nodeType;
|
||||
// ...
|
||||
};
|
||||
|
||||
interface EventTarget {
|
||||
void addEventListener(DOMString type,
|
||||
EventListener listener,
|
||||
boolean useCapture);
|
||||
// ...
|
||||
};
|
||||
|
||||
Node implements EventTarget;
|
|
@ -0,0 +1,12 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface OrderedMap {
|
||||
readonly attribute unsigned long size;
|
||||
|
||||
getter any getByIndex(unsigned long index);
|
||||
setter void setByIndex(unsigned long index, any value);
|
||||
deleter void removeByIndex(unsigned long index);
|
||||
|
||||
getter any get(DOMString name);
|
||||
setter creator void set(DOMString name, any value);
|
||||
deleter void remove(DOMString name);
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
interface Animal {
|
||||
|
||||
// A simple attribute that can be set to any string value.
|
||||
readonly attribute DOMString name;
|
||||
};
|
||||
|
||||
interface Person : Animal {
|
||||
|
||||
// An attribute whose value cannot be assigned to.
|
||||
readonly attribute unsigned short age;
|
||||
|
||||
// An attribute that can raise an exception if it is set to an invalid value.
|
||||
// Its getter behavior is inherited from Animal, and need not be specified
|
||||
// the description of Person.
|
||||
inherit attribute DOMString name;
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Animal {
|
||||
attribute DOMString name;
|
||||
};
|
||||
|
||||
interface Human : Animal {
|
||||
attribute Dog pet;
|
||||
};
|
||||
|
||||
interface Dog : Animal {
|
||||
attribute Human owner;
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
interface SessionManager {
|
||||
Session getSessionForUser(DOMString username);
|
||||
readonly attribute unsigned long sessionCount;
|
||||
|
||||
Session iterator;
|
||||
};
|
||||
|
||||
interface Session {
|
||||
readonly attribute DOMString username;
|
||||
// ...
|
||||
};
|
||||
|
||||
interface SessionManager2 {
|
||||
Session2 getSessionForUser(DOMString username);
|
||||
readonly attribute unsigned long sessionCount;
|
||||
|
||||
Session2 iterator = SessionIterator;
|
||||
};
|
||||
|
||||
interface Session2 {
|
||||
readonly attribute DOMString username;
|
||||
// ...
|
||||
};
|
||||
|
||||
interface SessionIterator {
|
||||
readonly attribute unsigned long remainingSessions;
|
||||
};
|
||||
|
||||
interface NodeList {
|
||||
Node iterator = NodeIterator;
|
||||
};
|
||||
|
||||
interface NodeIterator {
|
||||
Node iterator object;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
// Extracted from https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ on 2014-05-06
|
||||
|
||||
[MapClass(DOMString, DOMString)]
|
||||
interface HeaderMap {
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
[NamedConstructor=Audio,
|
||||
NamedConstructor=Audio(DOMString src)]
|
||||
interface HTMLAudioElement : HTMLMediaElement {
|
||||
// ...
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
[NoInterfaceObject]
|
||||
interface Query {
|
||||
any lookupEntry(unsigned long key);
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface MyConstants {
|
||||
const boolean? ARE_WE_THERE_YET = false;
|
||||
};
|
||||
|
||||
interface Node {
|
||||
readonly attribute DOMString? namespaceURI;
|
||||
// ...
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
// Extracted from WebIDL spec 2011-05-23
|
||||
|
||||
interface A {
|
||||
// ...
|
||||
};
|
||||
interface B {
|
||||
// ...
|
||||
};
|
||||
interface C {
|
||||
void f(A? x);
|
||||
void f(B? x);
|
||||
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface ColorCreator {
|
||||
object createColor(float v1, float v2, float v3, optional float alpha = 3.5);
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface A {
|
||||
// ...
|
||||
};
|
||||
|
||||
interface B {
|
||||
// ...
|
||||
};
|
||||
|
||||
interface C {
|
||||
void f(A x);
|
||||
void f(B x);
|
||||
};
|
||||
|
||||
interface A {
|
||||
/* f1 */ void f(DOMString a);
|
||||
/* f2 */ void f([AllowAny] DOMString a, DOMString b, float... c);
|
||||
/* f3 */ void f();
|
||||
/* f4 */ void f(long a, DOMString b, optional DOMString c, float... d);
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
[OverrideBuiltins]
|
||||
interface StringMap2 {
|
||||
readonly attribute unsigned long length;
|
||||
getter DOMString lookup(DOMString key);
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
interface Foo {
|
||||
attribute DOMString bar;
|
||||
};
|
||||
|
||||
partial interface Foo {
|
||||
attribute DOMString quux;
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
interface Primitives {
|
||||
attribute boolean truth;
|
||||
attribute byte character;
|
||||
attribute octet value;
|
||||
attribute short number;
|
||||
attribute unsigned short positive;
|
||||
attribute long big;
|
||||
attribute unsigned long bigpositive;
|
||||
attribute long long bigbig;
|
||||
attribute unsigned long long bigbigpositive;
|
||||
attribute float real;
|
||||
attribute double bigreal;
|
||||
attribute unrestricted float realwithinfinity;
|
||||
attribute unrestricted double bigrealwithinfinity;
|
||||
attribute DOMString string;
|
||||
attribute ByteString bytes;
|
||||
attribute Date date;
|
||||
attribute RegExp regexp;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
[PrototypeRoot]
|
||||
interface Node {
|
||||
readonly attribute unsigned short nodeType;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Person {
|
||||
[PutForwards=full] readonly attribute Name name;
|
||||
attribute unsigned short age;
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Dimensions {
|
||||
attribute unsigned long width;
|
||||
attribute unsigned long height;
|
||||
};
|
||||
|
||||
exception NoPointerDevice { };
|
||||
|
||||
interface Button {
|
||||
|
||||
// An operation that takes no arguments, returns a boolean
|
||||
boolean isMouseOver();
|
||||
|
||||
// Overloaded operations.
|
||||
void setDimensions(Dimensions size);
|
||||
void setDimensions(unsigned long width, unsigned long height);
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Counter {
|
||||
[Replaceable] readonly attribute unsigned long value;
|
||||
void increment();
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
// edited to remove sequence as attributes, now invalid
|
||||
interface Canvas {
|
||||
void drawPolygon(sequence<float> coordinates);
|
||||
sequence<float> getInflectionPoints();
|
||||
// ...
|
||||
};
|
||||
|
||||
// Make sure sequence can still be registered as a type.
|
||||
interface Foo {
|
||||
sequence bar();
|
||||
};
|
|
@ -0,0 +1,64 @@
|
|||
interface Transaction {
|
||||
readonly attribute Account from;
|
||||
readonly attribute Account to;
|
||||
readonly attribute float amount;
|
||||
readonly attribute DOMString description;
|
||||
readonly attribute unsigned long number;
|
||||
|
||||
serializer;
|
||||
};
|
||||
|
||||
interface Account {
|
||||
attribute DOMString name;
|
||||
attribute unsigned long number;
|
||||
serializer DOMString serialize();
|
||||
};
|
||||
|
||||
interface Transaction2 {
|
||||
readonly attribute Account2 from;
|
||||
readonly attribute Account2 to;
|
||||
readonly attribute float amount;
|
||||
readonly attribute DOMString description;
|
||||
readonly attribute unsigned long number;
|
||||
|
||||
serializer = { from, to, amount, description };
|
||||
};
|
||||
|
||||
interface Account2 {
|
||||
attribute DOMString name;
|
||||
attribute unsigned long number;
|
||||
serializer = number;
|
||||
};
|
||||
|
||||
interface Account3 {
|
||||
attribute DOMString name;
|
||||
attribute unsigned long number;
|
||||
|
||||
serializer = { attribute };
|
||||
};
|
||||
|
||||
interface Account4 {
|
||||
getter object getItem(unsigned long index);
|
||||
serializer = { getter };
|
||||
};
|
||||
|
||||
interface Account5 : Account {
|
||||
attribute DOMString secondname;
|
||||
serializer = { inherit, secondname };
|
||||
};
|
||||
|
||||
interface Account6 : Account {
|
||||
attribute DOMString secondname;
|
||||
serializer = { inherit, attribute };
|
||||
};
|
||||
|
||||
interface Account7 {
|
||||
attribute DOMString name;
|
||||
attribute unsigned long number;
|
||||
serializer = [ name, number ];
|
||||
};
|
||||
|
||||
interface Account8 {
|
||||
getter object getItem(unsigned long index);
|
||||
serializer = [ getter ];
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
interface Point { /* ... */ };
|
||||
|
||||
interface Circle {
|
||||
attribute float cx;
|
||||
attribute float cy;
|
||||
attribute float radius;
|
||||
|
||||
static readonly attribute long triangulationCount;
|
||||
static Point triangulate(Circle c1, Circle c2, Circle c3);
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
[Constructor]
|
||||
interface Student {
|
||||
attribute unsigned long id;
|
||||
stringifier attribute DOMString name;
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// Extracted from http://dev.w3.org/2006/webapi/WebIDL/ on 2011-05-06
|
||||
[Constructor]
|
||||
interface Student {
|
||||
attribute unsigned long id;
|
||||
attribute DOMString? familyName;
|
||||
attribute DOMString givenName;
|
||||
|
||||
stringifier DOMString ();
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue