Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: update WPT harness #33770

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/node_url.cc
Expand Up @@ -779,6 +779,8 @@ bool ToASCII(const std::string& input, std::string* output) {
MaybeStackBuffer<char> buf;
if (i18n::ToASCII(&buf, input.c_str(), input.length()) < 0)
return false;
if (buf.length() == 0)
return false;
output->assign(*buf, buf.length());
return true;
}
Expand Down Expand Up @@ -2084,8 +2086,6 @@ void URL::Parse(const char* input,
url->flags |= URL_FLAGS_HAS_FRAGMENT;
url->fragment = std::move(buffer);
break;
case 0:
break;
default:
AppendOrEscape(&buffer, ch, FRAGMENT_ENCODE_SET);
}
Expand Down
15 changes: 8 additions & 7 deletions test/fixtures/wpt/README.md
Expand Up @@ -10,14 +10,15 @@ See [test/wpt](../../wpt/README.md) for information on how these tests are run.

Last update:

- console: https://github.com/web-platform-tests/wpt/tree/9786a4b131/console
- encoding: https://github.com/web-platform-tests/wpt/tree/5059d2c777/encoding
- url: https://github.com/web-platform-tests/wpt/tree/43feb7f612/url
- resources: https://github.com/web-platform-tests/wpt/tree/e1fddfbf80/resources
- interfaces: https://github.com/web-platform-tests/wpt/tree/8ada332aea/interfaces
- html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/0c3bed38df/html/webappapis/microtask-queuing
- html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/ddfe9c089b/html/webappapis/timers
- console: https://github.com/web-platform-tests/wpt/tree/3b1f72e99a/console
- encoding: https://github.com/web-platform-tests/wpt/tree/11e6941923/encoding
- url: https://github.com/web-platform-tests/wpt/tree/551c9d604f/url
- resources: https://github.com/web-platform-tests/wpt/tree/55e9dc7f5e/resources
- interfaces: https://github.com/web-platform-tests/wpt/tree/4471cda31b/interfaces
- html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/2c5c3c4c27/html/webappapis/microtask-queuing
- html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/264f12bc7b/html/webappapis/timers
- hr-time: https://github.com/web-platform-tests/wpt/tree/a5d1774ecf/hr-time
- common: https://github.com/web-platform-tests/wpt/tree/4dacb6e2ff/common

[Web Platform Tests]: https://github.com/web-platform-tests/wpt
[`git node wpt`]: https://github.com/nodejs/node-core-utils/blob/master/docs/git-node.md#git-node-wpt
3 changes: 3 additions & 0 deletions test/fixtures/wpt/common/META.yml
@@ -0,0 +1,3 @@
suggested_reviewers:
- zqzhang
- deniak
116 changes: 116 additions & 0 deletions test/fixtures/wpt/common/PrefixedLocalStorage.js
@@ -0,0 +1,116 @@
/**
* Supports pseudo-"namespacing" localStorage for a given test
* by generating and using a unique prefix for keys. Why trounce on other
* tests' localStorage items when you can keep it "separated"?
*
* PrefixedLocalStorageTest: Instantiate in testharness.js tests to generate
* a new unique-ish prefix
* PrefixedLocalStorageResource: Instantiate in supporting test resource
* files to use/share a prefix generated by a test.
*/
var PrefixedLocalStorage = function () {
this.prefix = ''; // Prefix for localStorage keys
this.param = 'prefixedLocalStorage'; // Param to use in querystrings
};

PrefixedLocalStorage.prototype.clear = function () {
if (this.prefix === '') { return; }
Object.keys(localStorage).forEach(sKey => {
if (sKey.indexOf(this.prefix) === 0) {
localStorage.removeItem(sKey);
}
});
};

/**
* Append/replace prefix parameter and value in URI querystring
* Use to generate URLs to resource files that will share the prefix.
*/
PrefixedLocalStorage.prototype.url = function (uri) {
function updateUrlParameter (uri, key, value) {
var i = uri.indexOf('#');
var hash = (i === -1) ? '' : uri.substr(i);
uri = (i === -1) ? uri : uri.substr(0, i);
var re = new RegExp(`([?&])${key}=.*?(&|$)`, 'i');
var separator = uri.indexOf('?') !== -1 ? '&' : '?';
uri = (uri.match(re)) ? uri.replace(re, `$1${key}=${value}$2`) :
`${uri}${separator}${key}=${value}`;
return uri + hash;
}
return updateUrlParameter(uri, this.param, this.prefix);
};

PrefixedLocalStorage.prototype.prefixedKey = function (baseKey) {
return `${this.prefix}${baseKey}`;
};

PrefixedLocalStorage.prototype.setItem = function (baseKey, value) {
localStorage.setItem(this.prefixedKey(baseKey), value);
};

/**
* Listen for `storage` events pertaining to a particular key,
* prefixed with this object's prefix. Ignore when value is being set to null
* (i.e. removeItem).
*/
PrefixedLocalStorage.prototype.onSet = function (baseKey, fn) {
window.addEventListener('storage', e => {
var match = this.prefixedKey(baseKey);
if (e.newValue !== null && e.key.indexOf(match) === 0) {
fn.call(this, e);
}
});
};

/*****************************************************************************
* Use in a testharnessjs test to generate a new key prefix.
* async_test(t => {
* var prefixedStorage = new PrefixedLocalStorageTest();
* t.add_cleanup(() => prefixedStorage.cleanup());
* /...
* });
*/
var PrefixedLocalStorageTest = function () {
PrefixedLocalStorage.call(this);
this.prefix = `${document.location.pathname}-${Math.random()}-${Date.now()}-`;
};
PrefixedLocalStorageTest.prototype = Object.create(PrefixedLocalStorage.prototype);
PrefixedLocalStorageTest.prototype.constructor = PrefixedLocalStorageTest;

/**
* Use in a cleanup function to clear out prefixed entries in localStorage
*/
PrefixedLocalStorageTest.prototype.cleanup = function () {
this.setItem('closeAll', 'true');
this.clear();
};

/*****************************************************************************
* Use in test resource files to share a prefix generated by a
* PrefixedLocalStorageTest. Will look in URL querystring for prefix.
* Setting `close_on_cleanup` opt truthy will make this script's window listen
* for storage `closeAll` event from controlling test and close itself.
*
* var PrefixedLocalStorageResource({ close_on_cleanup: true });
*/
var PrefixedLocalStorageResource = function (options) {
PrefixedLocalStorage.call(this);
this.options = Object.assign({}, {
close_on_cleanup: false
}, options || {});
// Check URL querystring for prefix to use
var regex = new RegExp(`[?&]${this.param}(=([^&#]*)|&|#|$)`),
results = regex.exec(document.location.href);
if (results && results[2]) {
this.prefix = results[2];
}
// Optionally have this window close itself when the PrefixedLocalStorageTest
// sets a `closeAll` item.
if (this.options.close_on_cleanup) {
this.onSet('closeAll', () => {
window.close();
});
}
};
PrefixedLocalStorageResource.prototype = Object.create(PrefixedLocalStorage.prototype);
PrefixedLocalStorageResource.prototype.constructor = PrefixedLocalStorageResource;
1 change: 1 addition & 0 deletions test/fixtures/wpt/common/PrefixedLocalStorage.js.headers
@@ -0,0 +1 @@
Content-Type: text/javascript; charset=utf-8
100 changes: 100 additions & 0 deletions test/fixtures/wpt/common/PrefixedPostMessage.js
@@ -0,0 +1,100 @@
/**
* Supports pseudo-"namespacing" for window-posted messages for a given test
* by generating and using a unique prefix that gets wrapped into message
* objects. This makes it more feasible to have multiple tests that use
* `window.postMessage` in a single test file. Basically, make it possible
* for the each test to listen for only the messages that are pertinent to it.
*
* 'Prefix' not an elegant term to use here but this models itself after
* PrefixedLocalStorage.
*
* PrefixedMessageTest: Instantiate in testharness.js tests to generate
* a new unique-ish prefix that can be used by other test support files
* PrefixedMessageResource: Instantiate in supporting test resource
* files to use/share a prefix generated by a test.
*/
var PrefixedMessage = function () {
this.prefix = '';
this.param = 'prefixedMessage'; // Param to use in querystrings
};

/**
* Generate a URL that adds/replaces param with this object's prefix
* Use to link to test support files that make use of
* PrefixedMessageResource.
*/
PrefixedMessage.prototype.url = function (uri) {
function updateUrlParameter (uri, key, value) {
var i = uri.indexOf('#');
var hash = (i === -1) ? '' : uri.substr(i);
uri = (i === -1) ? uri : uri.substr(0, i);
var re = new RegExp(`([?&])${key}=.*?(&|$)`, 'i');
var separator = uri.indexOf('?') !== -1 ? '&' : '?';
uri = (uri.match(re)) ? uri.replace(re, `$1${key}=${value}$2`) :
`${uri}${separator}${key}=${value}`;
return uri + hash;
}
return updateUrlParameter(uri, this.param, this.prefix);
};

/**
* Add an eventListener on `message` but only invoke the given callback
* for messages whose object contains this object's prefix. Remove the
* event listener once the anticipated message has been received.
*/
PrefixedMessage.prototype.onMessage = function (fn) {
window.addEventListener('message', e => {
if (typeof e.data === 'object' && e.data.hasOwnProperty('prefix')) {
if (e.data.prefix === this.prefix) {
// Only invoke callback when `data` is an object containing
// a `prefix` key with this object's prefix value
// Note fn is invoked with "unwrapped" data first, then the event `e`
// (which contains the full, wrapped e.data should it be needed)
fn.call(this, e.data.data, e);
window.removeEventListener('message', fn);
}
}
});
};

/**
* Instantiate in a test file (e.g. during `setup`) to create a unique-ish
* prefix that can be shared by support files
*/
var PrefixedMessageTest = function () {
PrefixedMessage.call(this);
this.prefix = `${document.location.pathname}-${Math.random()}-${Date.now()}-`;
};
PrefixedMessageTest.prototype = Object.create(PrefixedMessage.prototype);
PrefixedMessageTest.prototype.constructor = PrefixedMessageTest;

/**
* Instantiate in a test support script to use a "prefix" generated by a
* PrefixedMessageTest in a controlling test file. It will look for
* the prefix in a URL param (see also PrefixedMessage#url)
*/
var PrefixedMessageResource = function () {
PrefixedMessage.call(this);
// Check URL querystring for prefix to use
var regex = new RegExp(`[?&]${this.param}(=([^&#]*)|&|#|$)`),
results = regex.exec(document.location.href);
if (results && results[2]) {
this.prefix = results[2];
}
};
PrefixedMessageResource.prototype = Object.create(PrefixedMessage.prototype);
PrefixedMessageResource.prototype.constructor = PrefixedMessageResource;

/**
* This is how a test resource document can "send info" to its
* opener context. It will whatever message is being sent (`data`) in
* an object that injects the prefix.
*/
PrefixedMessageResource.prototype.postToOpener = function (data) {
if (window.opener) {
window.opener.postMessage({
prefix: this.prefix,
data: data
}, '*');
}
};
1 change: 1 addition & 0 deletions test/fixtures/wpt/common/PrefixedPostMessage.js.headers
@@ -0,0 +1 @@
Content-Type: text/javascript; charset=utf-8
10 changes: 10 additions & 0 deletions test/fixtures/wpt/common/README.md
@@ -0,0 +1,10 @@
The files in this directory are non-infrastructure support files that can be used by tests.

* `blank.html` - An empty HTML document.
* `domain-setter.sub.html` - An HTML document that sets `document.domain`.
* `dummy.xhtml` - An XHTML document.
* `dummy.xml` - An XML document.
* `text-plain.txt` - A text/plain document.
* `*.js` - Utility scripts. These are documented in the source.
* `*.py` - wptserve [Python Handlers](https://web-platform-tests.org/writing-tests/python-handlers/). These are documented in the source.
* `security-features` - Documented in `security-features/README.md`.
31 changes: 31 additions & 0 deletions test/fixtures/wpt/common/arrays.js
@@ -0,0 +1,31 @@
/**
* Callback for checking equality of c and d.
*
* @callback equalityCallback
* @param {*} c
* @param {*} d
* @returns {boolean}
*/

/**
* Returns true if the given arrays are equal. Optionally can pass an equality function.
* @param {Array} a
* @param {Array} b
* @param {equalityCallback} callbackFunction - defaults to `c === d`
* @returns {boolean}
*/
export function areArraysEqual(a, b, equalityFunction = (c, d) => { return c === d; }) {
try {
if (a.length !== b.length)
return false;

for (let i = 0; i < a.length; i++) {
if (!equalityFunction(a[i], b[i]))
return false;
}
} catch (ex) {
return false;
}

return true;
}
Empty file.
8 changes: 8 additions & 0 deletions test/fixtures/wpt/common/domain-setter.sub.html
@@ -0,0 +1,8 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>A page that will likely be same-origin-domain but not same-origin</title>

<script>
"use strict";
document.domain = "{{host}}";
</script>
2 changes: 2 additions & 0 deletions test/fixtures/wpt/common/dummy.xhtml
@@ -0,0 +1,2 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Dummy XHTML document</title></head><body /></html>
1 change: 1 addition & 0 deletions test/fixtures/wpt/common/dummy.xml
@@ -0,0 +1 @@
<foo>Dummy XML document</foo>
58 changes: 58 additions & 0 deletions test/fixtures/wpt/common/get-host-info.sub.js
@@ -0,0 +1,58 @@
/**
* Host information for cross-origin tests.
* @returns {Object} with properties for different host information.
*/
function get_host_info() {

var HTTP_PORT = '{{ports[http][0]}}';
var HTTP_PORT2 = '{{ports[http][1]}}';
var HTTPS_PORT = '{{ports[https][0]}}';
var HTTPS_PORT2 = '{{ports[https][1]}}';
var PROTOCOL = self.location.protocol;
var IS_HTTPS = (PROTOCOL == "https:");
var HTTP_PORT_ELIDED = HTTP_PORT == "80" ? "" : (":" + HTTP_PORT);
var HTTP_PORT2_ELIDED = HTTP_PORT2 == "80" ? "" : (":" + HTTP_PORT2);
var HTTPS_PORT_ELIDED = HTTPS_PORT == "443" ? "" : (":" + HTTPS_PORT);
var PORT_ELIDED = IS_HTTPS ? HTTPS_PORT_ELIDED : HTTP_PORT_ELIDED;
var ORIGINAL_HOST = '{{host}}';
var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www1.' + ORIGINAL_HOST);
var OTHER_HOST = '{{domains[www2]}}';
var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('{{hosts[alt][]}}');

return {
HTTP_PORT: HTTP_PORT,
HTTP_PORT2: HTTP_PORT2,
HTTPS_PORT: HTTPS_PORT,
HTTPS_PORT2: HTTPS_PORT2,
ORIGINAL_HOST: ORIGINAL_HOST,
REMOTE_HOST: REMOTE_HOST,

ORIGIN: PROTOCOL + "//" + ORIGINAL_HOST + PORT_ELIDED,
HTTP_ORIGIN: 'http://' + ORIGINAL_HOST + HTTP_PORT_ELIDED,
HTTPS_ORIGIN: 'https://' + ORIGINAL_HOST + HTTPS_PORT_ELIDED,
HTTPS_ORIGIN_WITH_CREDS: 'https://foo:bar@' + ORIGINAL_HOST + HTTPS_PORT_ELIDED,
HTTP_ORIGIN_WITH_DIFFERENT_PORT: 'http://' + ORIGINAL_HOST + HTTP_PORT2_ELIDED,
REMOTE_ORIGIN: PROTOCOL + "//" + REMOTE_HOST + PORT_ELIDED,
HTTP_REMOTE_ORIGIN: 'http://' + REMOTE_HOST + HTTP_PORT_ELIDED,
HTTP_NOTSAMESITE_ORIGIN: 'http://' + NOTSAMESITE_HOST + HTTP_PORT_ELIDED,
HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT: 'http://' + REMOTE_HOST + HTTP_PORT2_ELIDED,
HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + HTTPS_PORT_ELIDED,
HTTPS_REMOTE_ORIGIN_WITH_CREDS: 'https://foo:bar@' + REMOTE_HOST + HTTPS_PORT_ELIDED,
HTTPS_NOTSAMESITE_ORIGIN: 'https://' + NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
UNAUTHENTICATED_ORIGIN: 'http://' + OTHER_HOST + HTTP_PORT_ELIDED,
AUTHENTICATED_ORIGIN: 'https://' + OTHER_HOST + HTTPS_PORT_ELIDED
};
}

/**
* When a default port is used, location.port returns the empty string.
* This function attempts to provide an exact port, assuming we are running under wptserve.
* @param {*} loc - can be Location/<a>/<area>/URL, but assumes http/https only.
* @returns {string} The port number.
*/
function get_port(loc) {
if (loc.port) {
return loc.port;
}
return loc.protocol === 'https:' ? '443' : '80';
}
1 change: 1 addition & 0 deletions test/fixtures/wpt/common/get-host-info.sub.js.headers
@@ -0,0 +1 @@
Content-Type: text/javascript; charset=utf-8