mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 12:20:56 +00:00
Merge autoland to mozilla-central. a=merge
This commit is contained in:
commit
2bbb0c0a90
@ -171,7 +171,8 @@ static const uint64_t kCacheInitialized = ((uint64_t)0x1) << 63;
|
||||
return mRole == roles::GROUPING || mRole == roles::RADIO_GROUP ||
|
||||
mRole == roles::FIGURE || mRole == roles::GRAPHIC ||
|
||||
mRole == roles::DOCUMENT || mRole == roles::OUTLINE ||
|
||||
mRole == roles::ARTICLE;
|
||||
mRole == roles::ARTICLE || mRole == roles::ENTRY ||
|
||||
mRole == roles::SPINBUTTON;
|
||||
}
|
||||
|
||||
- (mozilla::a11y::Accessible*)geckoAccessible {
|
||||
|
@ -89,3 +89,23 @@ addAccessibleTask(
|
||||
ok(!article.getAttributeValue("AXTitle"));
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Test text and number inputs supply only labels not titles
|
||||
*/
|
||||
addAccessibleTask(
|
||||
`<label for="input">Your favorite number?</label><input type="text" name="input" value="11" id="input" aria-label="The best number you know of">`,
|
||||
async (browser, accDoc) => {
|
||||
let input = getNativeInterface(accDoc, "input");
|
||||
is(input.getAttributeValue("AXDescription"), "The best number you know of");
|
||||
ok(!input.getAttributeValue("AXTitle"));
|
||||
let evt = waitForEvent(EVENT_SHOW, "input");
|
||||
await SpecialPowers.spawn(browser, [], () => {
|
||||
content.document.getElementById("input").setAttribute("type", "number");
|
||||
});
|
||||
await evt;
|
||||
input = getNativeInterface(accDoc, "input");
|
||||
is(input.getAttributeValue("AXDescription"), "The best number you know of");
|
||||
ok(!input.getAttributeValue("AXTitle"));
|
||||
}
|
||||
);
|
||||
|
@ -776,7 +776,7 @@ function setCertErrorDetails(event) {
|
||||
desc,
|
||||
"cert-error-symantec-distrust-description",
|
||||
{
|
||||
HOST_NAME,
|
||||
hostname: HOST_NAME,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -31,8 +31,10 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* 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/. */
|
||||
// If we're in a subdialog, then this is a spotlight modal
|
||||
const page = document.querySelector(":root[dialogroot=true]") ? "spotlight" : "about:welcome";
|
||||
// If we're in a subdialog, then this is a spotlight modal.
|
||||
// Otherwise, this is about:welcome or a Feature Callout
|
||||
// in another "about" page and we should return the current page.
|
||||
const page = document.querySelector(":root[dialogroot=true]") ? "spotlight" : document.location.href;
|
||||
const AboutWelcomeUtils = {
|
||||
handleUserAction(action) {
|
||||
window.AWSendToParent("SPECIAL_ACTION", action);
|
||||
|
@ -2,10 +2,12 @@
|
||||
* 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/. */
|
||||
|
||||
// If we're in a subdialog, then this is a spotlight modal
|
||||
// If we're in a subdialog, then this is a spotlight modal.
|
||||
// Otherwise, this is about:welcome or a Feature Callout
|
||||
// in another "about" page and we should return the current page.
|
||||
const page = document.querySelector(":root[dialogroot=true]")
|
||||
? "spotlight"
|
||||
: "about:welcome";
|
||||
: document.location.href;
|
||||
|
||||
export const AboutWelcomeUtils = {
|
||||
handleUserAction(action) {
|
||||
|
@ -29,6 +29,7 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
"resource://activity-stream/lib/ASRouterTriggerListeners.jsm",
|
||||
KintoHttpClient: "resource://services-common/kinto-http-client.js",
|
||||
Downloader: "resource://services-settings/Attachments.jsm",
|
||||
RemoteImages: "resource://activity-stream/lib/RemoteImages.jsm",
|
||||
RemoteL10n: "resource://activity-stream/lib/RemoteL10n.jsm",
|
||||
ExperimentAPI: "resource://nimbus/ExperimentAPI.jsm",
|
||||
NimbusFeatures: "resource://nimbus/ExperimentAPI.jsm",
|
||||
@ -97,6 +98,14 @@ const TOPIC_EXPERIMENT_FORCE_ENROLLED = "nimbus:force-enroll";
|
||||
const USE_REMOTE_L10N_PREF =
|
||||
"browser.newtabpage.activity-stream.asrouter.useRemoteL10n";
|
||||
|
||||
const MESSAGING_EXPERIMENTS_DEFAULT_FEATURES = [
|
||||
"cfr",
|
||||
"infobar",
|
||||
"moments-page",
|
||||
"pbNewtab",
|
||||
"spotlight",
|
||||
];
|
||||
|
||||
// Experiment groups that need to report the reach event in Messaging-Experiments.
|
||||
// If you're adding new groups to it, make sure they're also added in the
|
||||
// `messaging_experiments.reach.objects` defined in "toolkit/components/telemetry/Events.yaml"
|
||||
@ -325,15 +334,27 @@ const MessageLoaderUtils = {
|
||||
return RemoteSettings(bucket).get();
|
||||
},
|
||||
|
||||
/**
|
||||
* Return messages from active Nimbus experiments.
|
||||
*
|
||||
* @param {object} provider A messaging experiments provider.
|
||||
* @param {string[]?} provider.featureIds
|
||||
* An optional array of Nimbus feature IDs to check for
|
||||
* messaging experiments. If not provided, we will fall
|
||||
* back to the set of default features. Otherwise, if
|
||||
* provided and empty, we will not ingest messages from any
|
||||
* features.
|
||||
*
|
||||
* @return {object[]} The list of messages from active experiments, as well as
|
||||
* the messages defined in unenrolled branches so that they
|
||||
* reach events can be recorded (if we record reach events
|
||||
* for that feature).
|
||||
*/
|
||||
async _experimentsAPILoader(provider) {
|
||||
// Allow tests to override the set of featureIds
|
||||
const featureIds = provider.featureIds ?? [
|
||||
"cfr",
|
||||
"infobar",
|
||||
"moments-page",
|
||||
"pbNewtab",
|
||||
"spotlight",
|
||||
];
|
||||
const featureIds = Array.isArray(provider.featureIds)
|
||||
? provider.featureIds
|
||||
: MESSAGING_EXPERIMENTS_DEFAULT_FEATURES;
|
||||
let experiments = [];
|
||||
for (const featureId of featureIds) {
|
||||
let featureAPI = lazy.NimbusFeatures[featureId];
|
||||
@ -552,6 +573,7 @@ class _ASRouter {
|
||||
errors: [],
|
||||
localeInUse: Services.locale.appLocaleAsBCP47,
|
||||
};
|
||||
this._experimentChangedListeners = new Map();
|
||||
this._triggerHandler = this._triggerHandler.bind(this);
|
||||
this._localProviders = localProviders;
|
||||
this.blockMessageById = this.blockMessageById.bind(this);
|
||||
@ -636,6 +658,13 @@ class _ASRouter {
|
||||
);
|
||||
provider.url = Services.urlFormatter.formatURL(provider.url);
|
||||
}
|
||||
if (provider.id === "messaging-experiments") {
|
||||
// By default, the messaging-experiments provider lacks a featureIds
|
||||
// property, so fall back to the list of default features.
|
||||
if (!provider.featureIds) {
|
||||
provider.featureIds = MESSAGING_EXPERIMENTS_DEFAULT_FEATURES;
|
||||
}
|
||||
}
|
||||
// Reset provider update timestamp to force message refresh
|
||||
provider.lastUpdated = undefined;
|
||||
return provider;
|
||||
@ -652,6 +681,21 @@ class _ASRouter {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// If the feature IDs of the messaging-experiments provider has changed,
|
||||
// then we need to update which features for which we are listening to
|
||||
// changes.
|
||||
const prevExpts = previousProviders.find(
|
||||
p => p.id === "messaging-experiments"
|
||||
);
|
||||
const expts = providers.find(p => p.id === "messaging-experiments");
|
||||
|
||||
this._onFeatureListChanged(
|
||||
prevExpts?.enabled ? prevExpts.featureIds : [],
|
||||
expts?.enabled ? expts.featureIds : []
|
||||
);
|
||||
}
|
||||
|
||||
return this.setState(prevState => ({
|
||||
providers,
|
||||
// Clear any messages from removed providers
|
||||
@ -1848,7 +1892,7 @@ class _ASRouter {
|
||||
await lazy.ToolbarPanelHub._hideToolbarButton(win);
|
||||
}
|
||||
|
||||
async _onExperimentForceEnrolled(subject, topic, data) {
|
||||
async _onExperimentForceEnrolled(subject, topic, slug) {
|
||||
const experimentProvider = this.state.providers.find(
|
||||
p => p.id === "messaging-experiments"
|
||||
);
|
||||
@ -1856,8 +1900,89 @@ class _ASRouter {
|
||||
return;
|
||||
}
|
||||
|
||||
const branch = lazy.ExperimentAPI.getActiveBranch({ slug });
|
||||
const features = branch.features ?? [branch.feature];
|
||||
const featureIds = features.map(feature => feature.featureId);
|
||||
|
||||
this._onFeaturesUpdated(...featureIds);
|
||||
|
||||
await this.loadMessagesFromAllProviders([experimentProvider]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a change to the list of featureIds that the messaging-experiments
|
||||
* provider is watching.
|
||||
*
|
||||
* This normally occurs when ASRouter update message providers, which happens
|
||||
* every startup and when the messaging-experiment provider pref changes.
|
||||
*
|
||||
* On startup, |oldFeatures| will be an empty array and we will subscribe to
|
||||
* everything in |newFeatures|.
|
||||
*
|
||||
* When the pref changes, we unsubscribe from |oldFeatures - newFeatures| and
|
||||
* subscribe to |newFeatures - oldFeatures|. Features that are listed in both
|
||||
* sets do not have their subscription status changed. Pref changes are mostly
|
||||
* during unit tests.
|
||||
*
|
||||
* @param {string[]} oldFeatures The list of feature IDs we were previously
|
||||
* listening to for new experiments.
|
||||
* @param {string[]} newFeatures The list of feature IDs we are now listening
|
||||
* to for new experiments.
|
||||
*/
|
||||
_onFeatureListChanged(oldFeatures, newFeatures) {
|
||||
for (const featureId of oldFeatures) {
|
||||
if (!newFeatures.includes(featureId)) {
|
||||
const listener = this._experimentChangedListeners.get(featureId);
|
||||
this._experimentChangedListeners.delete(featureId);
|
||||
lazy.NimbusFeatures[featureId].off(listener);
|
||||
}
|
||||
}
|
||||
|
||||
const newlySubscribed = [];
|
||||
|
||||
for (const featureId of newFeatures) {
|
||||
if (!oldFeatures.includes(featureId)) {
|
||||
const listener = () => this._onFeaturesUpdated(featureId);
|
||||
this._experimentChangedListeners.set(featureId, listener);
|
||||
lazy.NimbusFeatures[featureId].onUpdate(listener);
|
||||
|
||||
newlySubscribed.push(featureId);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for any messages present in the newly subscribed to Nimbus features
|
||||
// so we can prefetch their remote images (if any).
|
||||
this._onFeaturesUpdated(...newlySubscribed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle updated experiment features.
|
||||
*
|
||||
* If there are messages for the feature, RemoteImages will prefetch any
|
||||
* images.
|
||||
*
|
||||
* @param {string[]} featureIds The feature IDs that have been updated.
|
||||
*/
|
||||
_onFeaturesUpdated(...featureIds) {
|
||||
const messages = [];
|
||||
|
||||
for (const featureId of featureIds) {
|
||||
const featureAPI = lazy.NimbusFeatures[featureId];
|
||||
// If there is no active experiment for the feature, this will return
|
||||
// null.
|
||||
if (lazy.ExperimentAPI.getExperimentMetaData({ featureId })) {
|
||||
// Otherwise, getAllVariables() will return the JSON blob for the
|
||||
// message.
|
||||
messages.push(featureAPI.getAllVariables());
|
||||
}
|
||||
}
|
||||
|
||||
// We are not awaiting this because we want these images to load in the
|
||||
// background.
|
||||
if (messages.length) {
|
||||
lazy.RemoteImages.prefetchImagesFor(messages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,11 +45,35 @@ const REMOTE_IMAGES_DB_PATH = PathUtils.join(REMOTE_IMAGES_PATH, "db.json");
|
||||
|
||||
const IMAGE_EXPIRY_DURATION = 30 * 24 * 60 * 60; // 30 days in seconds.
|
||||
|
||||
const PREFETCH_FINISHED_TOPIC = "remote-images:prefetch-finished";
|
||||
|
||||
/**
|
||||
* Inspectors for FxMS messages.
|
||||
*
|
||||
* Each member is the name of a FxMS template (spotlight, infobar, etc.) and
|
||||
* corresponds to a function that accepts a message and returns all record IDs
|
||||
* for remote images.
|
||||
*/
|
||||
const MessageInspectors = {
|
||||
spotlight(message) {
|
||||
if (
|
||||
message.content.template === "logo-and-content" &&
|
||||
message.content.logo?.imageId
|
||||
) {
|
||||
return [message.content.logo.imageId];
|
||||
}
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
||||
class _RemoteImages {
|
||||
#dbPromise;
|
||||
|
||||
#fetching;
|
||||
|
||||
constructor() {
|
||||
this.#dbPromise = null;
|
||||
this.#fetching = new Map();
|
||||
|
||||
RemoteSettings(RS_COLLECTION).on("sync", () => this.#onSync());
|
||||
|
||||
@ -193,6 +217,12 @@ class _RemoteImages {
|
||||
async #loadImpl(db, imageId) {
|
||||
const recordId = this.#getRecordId(imageId);
|
||||
|
||||
// If we are pre-fetching an image, we can piggy-back on that request.
|
||||
if (this.#fetching.has(imageId)) {
|
||||
const { record, arrayBuffer } = await this.#fetching.get(imageId);
|
||||
return new Blob([arrayBuffer], { type: record.data.attachment.mimetype });
|
||||
}
|
||||
|
||||
let blob;
|
||||
if (db.data.images[recordId]) {
|
||||
// We have previously fetched this image, we can load it from disk.
|
||||
@ -231,6 +261,9 @@ class _RemoteImages {
|
||||
}
|
||||
|
||||
#onSync() {
|
||||
// This is OK to run while pre-fetches are ocurring. Pre-fetches don't check
|
||||
// if there is a new version available, so there will be no race between
|
||||
// syncing an updated image and pre-fetching
|
||||
return this.withDb(async db => {
|
||||
await this.#cleanup(db);
|
||||
|
||||
@ -245,7 +278,7 @@ class _RemoteImages {
|
||||
.filter(
|
||||
entry => recordsById[entry.recordId]?.attachment.hash !== entry.hash
|
||||
)
|
||||
.map(entry => this.#download(db, entry.recordId, { refresh: true }))
|
||||
.map(entry => this.#download(db, entry.recordId, { fetchOnly: true }))
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -261,6 +294,8 @@ class _RemoteImages {
|
||||
* finished.
|
||||
*/
|
||||
async #cleanup(db) {
|
||||
// This may run while background fetches are happening. However, that
|
||||
// doesn't matter because those images will definitely not be expired.
|
||||
const now = Date.now();
|
||||
await Promise.all(
|
||||
Object.values(db.data.images)
|
||||
@ -330,39 +365,19 @@ class _RemoteImages {
|
||||
* @param {JSONFile} db The RemoteImages database.
|
||||
* @param {string} recordId The record ID of the image.
|
||||
* @param {object} options Options for downloading the image.
|
||||
* @param {boolean} options.refresh Whether or not the image is being
|
||||
* downloaded because it is out of sync with
|
||||
* Remote Settings. If true, the blob will be
|
||||
* written to disk and not returned.
|
||||
* Additionally, the |lastLoaded| field will
|
||||
* not be updated in its db entry.
|
||||
* @param {boolean} options.fetchOnly Whether or not to only fetch the image.
|
||||
*
|
||||
* @returns A promise that resolves with a Blob of the image data or rejects
|
||||
* with an Error.
|
||||
* @returns If |fetchOnly| is true, a promise that resolves to undefined.
|
||||
* If |fetchOnly| is false, a promise that resolves to a Blob of the
|
||||
* image data.
|
||||
*/
|
||||
async #download(db, recordId, { refresh = false } = {}) {
|
||||
const client = new lazy.KintoHttpClient(lazy.Utils.SERVER_URL);
|
||||
const record = await client
|
||||
.bucket(RS_MAIN_BUCKET)
|
||||
.collection(RS_COLLECTION)
|
||||
.getRecord(recordId);
|
||||
|
||||
const downloader = new lazy.Downloader(RS_MAIN_BUCKET, RS_COLLECTION);
|
||||
const arrayBuffer = await downloader.downloadAsBytes(record.data, {
|
||||
retries: RS_DOWNLOAD_MAX_RETRIES,
|
||||
});
|
||||
|
||||
// Cache to disk.
|
||||
const path = PathUtils.join(REMOTE_IMAGES_PATH, recordId);
|
||||
|
||||
// We do not await this promise because any other attempt to interact with
|
||||
// the file via IOUtils will have to synchronize via the IOUtils event queue
|
||||
// anyway.
|
||||
IOUtils.write(path, new Uint8Array(arrayBuffer));
|
||||
|
||||
async #download(db, recordId, { fetchOnly = false } = {}) {
|
||||
// It is safe to call #unsafeDownload here because we hold the db while the
|
||||
// entire download runs.
|
||||
const { record, arrayBuffer } = await this.#unsafeDownload(recordId);
|
||||
const { mimetype, hash } = record.data.attachment;
|
||||
|
||||
if (refresh) {
|
||||
if (fetchOnly) {
|
||||
Object.assign(db.data.images[recordId], { mimetype, hash });
|
||||
} else {
|
||||
db.data.images[recordId] = {
|
||||
@ -375,11 +390,177 @@ class _RemoteImages {
|
||||
|
||||
db.saveSoon();
|
||||
|
||||
if (!refresh) {
|
||||
return new Blob([arrayBuffer], { type: record.data.attachment.mimetype });
|
||||
if (fetchOnly) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return new Blob([arrayBuffer], { type: record.data.attachment.mimetype });
|
||||
}
|
||||
|
||||
/**
|
||||
* Download an image *without* holding a handle to the database.
|
||||
*
|
||||
* @param {string} recordId The record ID of the image to download
|
||||
*
|
||||
* @returns A promise that resolves to the RemoteSettings record and the
|
||||
* downloaded ArrayBuffer.
|
||||
*/
|
||||
async #unsafeDownload(recordId) {
|
||||
const client = new lazy.KintoHttpClient(lazy.Utils.SERVER_URL);
|
||||
|
||||
const record = await client
|
||||
.bucket(RS_MAIN_BUCKET)
|
||||
.collection(RS_COLLECTION)
|
||||
.getRecord(recordId);
|
||||
|
||||
const downloader = new lazy.Downloader(RS_MAIN_BUCKET, RS_COLLECTION);
|
||||
const arrayBuffer = await downloader.downloadAsBytes(record.data, {
|
||||
retries: RS_DOWNLOAD_MAX_RETRIES,
|
||||
});
|
||||
|
||||
const path = PathUtils.join(REMOTE_IMAGES_PATH, recordId);
|
||||
|
||||
// Cache to disk.
|
||||
//
|
||||
// We do not await this promise because any other attempt to interact with
|
||||
// the file via IOUtils will have to synchronize via the IOUtils event queue
|
||||
// anyway.
|
||||
//
|
||||
// This is OK to do without holding the db because cleanup will not touch
|
||||
// this image.
|
||||
IOUtils.write(path, new Uint8Array(arrayBuffer));
|
||||
|
||||
return { record, arrayBuffer };
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch images for the given messages.
|
||||
*
|
||||
* This will only acquire the db handle when we need to handle internal state
|
||||
* so that other consumers can interact with RemoteImages while pre-fetches
|
||||
* are happening.
|
||||
*
|
||||
* NB: This function is not intended to be awaited so that it can run the
|
||||
* fetches in the background.
|
||||
*
|
||||
* @param {object[]} messages The FxMS messages to prefetch images for.
|
||||
*/
|
||||
async prefetchImagesFor(messages) {
|
||||
// Collect the list of record IDs from the message, if we have an inspector
|
||||
// for it.
|
||||
const recordIds = messages
|
||||
.filter(
|
||||
message =>
|
||||
message.template && Object.hasOwn(MessageInspectors, message.template)
|
||||
)
|
||||
.flatMap(message => MessageInspectors[message.template](message))
|
||||
.map(imageId => this.#getRecordId(imageId));
|
||||
|
||||
// If we find some messages, grab the db lock and queue the downloads of
|
||||
// each.
|
||||
if (recordIds.length) {
|
||||
const promises = await this.withDb(
|
||||
db =>
|
||||
new Map(
|
||||
recordIds.reduce((entries, recordId) => {
|
||||
const promise = this.#beginPrefetch(db, recordId);
|
||||
|
||||
// If we already have the image, #beginPrefetching will return
|
||||
// null instead of a promise.
|
||||
if (promise !== null) {
|
||||
this.#fetching.set(recordId, promise);
|
||||
entries.push([recordId, promise]);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}, [])
|
||||
)
|
||||
);
|
||||
|
||||
// We have dropped db lock and the fetches will continue in the background.
|
||||
// If we do not drop the lock here, nothing can interact with RemoteImages
|
||||
// while we are pre-fetching.
|
||||
//
|
||||
// As each prefetch request finishes, they will individually grab the db
|
||||
// lock (inside #finishPrefetch or #handleFailedPrefetch) to update
|
||||
// internal state.
|
||||
const prefetchesFinished = Array.from(promises.entries()).map(
|
||||
([recordId, promise]) =>
|
||||
promise.then(
|
||||
result => this.#finishPrefetch(result),
|
||||
() => this.#handleFailedPrefetch(recordId)
|
||||
)
|
||||
);
|
||||
|
||||
// Wait for all prefetches to finish before we send our notification.
|
||||
await Promise.all(prefetchesFinished);
|
||||
|
||||
Services.obs.notifyObservers(null, PREFETCH_FINISHED_TOPIC);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the image for the given record ID has a database entry.
|
||||
* Begin pre-fetching the requested image if we do not already have it locally.
|
||||
*
|
||||
* @param {JSONFile} db The database.
|
||||
* @param {string} recordId The record ID of the image.
|
||||
*
|
||||
* @returns If the image is already cached locally, null is returned.
|
||||
* Otherwise, a promise that resolves to an object including the
|
||||
* recordId, the Remote Settings record, and the ArrayBuffer of the
|
||||
* downloaded file.
|
||||
*/
|
||||
#beginPrefetch(db, recordId) {
|
||||
if (!Object.hasOwn(db.data.images, recordId)) {
|
||||
// We kick off the download while we hold the db (so we can record the
|
||||
// promise in #fetches), but we do not ensure that the download completes
|
||||
// while we hold it.
|
||||
//
|
||||
// It is safe to call #unsafeDownload here and let the promises resolve
|
||||
// outside this function because we record the recordId and promise in
|
||||
// #fetching so any concurrent request to load the same image will re-use
|
||||
// that promise and not trigger a second download (and therefore IO).
|
||||
const promise = this.#unsafeDownload(recordId);
|
||||
this.#fetching.set(recordId, promise);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish prefetching an image.
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {object} options.record The Remote Settings record.
|
||||
*/
|
||||
#finishPrefetch({ record }) {
|
||||
return this.withDb(db => {
|
||||
const { id: recordId } = record.data;
|
||||
const { mimetype, hash } = record.data.attachment;
|
||||
|
||||
this.#fetching.delete(recordId);
|
||||
|
||||
db.data.images[recordId] = {
|
||||
recordId,
|
||||
mimetype,
|
||||
hash,
|
||||
lastLoaded: Date.now(),
|
||||
};
|
||||
|
||||
db.saveSoon();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the prefetch entry for a fetch that failed.
|
||||
*/
|
||||
#handleFailedPrefetch(recordId) {
|
||||
return this.withDb(db => {
|
||||
this.#fetching.delete(recordId);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,12 +3,24 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { ASRouter } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/ASRouter.jsm"
|
||||
);
|
||||
const { BrowserUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/BrowserUtils.jsm"
|
||||
);
|
||||
const { BrowserTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/BrowserTestUtils.jsm"
|
||||
);
|
||||
const { Downloader } = ChromeUtils.import(
|
||||
"resource://services-settings/Attachments.jsm"
|
||||
);
|
||||
const { ExperimentFakes } = ChromeUtils.import(
|
||||
"resource://testing-common/NimbusTestUtils.jsm"
|
||||
);
|
||||
const { PanelTestProvider } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/PanelTestProvider.jsm"
|
||||
);
|
||||
const {
|
||||
RemoteImages,
|
||||
REMOTE_IMAGES_PATH,
|
||||
@ -20,6 +32,11 @@ const { RemoteImagesTestUtils, RemoteSettingsServer } = ChromeUtils.import(
|
||||
const { RemoteSettings } = ChromeUtils.import(
|
||||
"resource://services-settings/remote-settings.js"
|
||||
);
|
||||
const { RemoteSettingsExperimentLoader } = ChromeUtils.import(
|
||||
"resource://nimbus/lib/RemoteSettingsExperimentLoader.jsm"
|
||||
);
|
||||
|
||||
const PREFETCH_FINISHED_TOPIC = "remote-images:prefetch-finished";
|
||||
|
||||
function dbWriteFinished(db) {
|
||||
// RemoteImages calls JSONFile.saveSoon(), so make sure that the DeferredTask
|
||||
@ -223,7 +240,7 @@ add_task(async function test_remoteImages_load_dedup() {
|
||||
);
|
||||
} finally {
|
||||
await stop();
|
||||
await RemoteImagesTestUtils.triggerCleanup();
|
||||
await RemoteImagesTestUtils.wipeCache();
|
||||
sandbox.restore();
|
||||
}
|
||||
});
|
||||
@ -305,8 +322,109 @@ add_task(async function test_remoteImages_sync() {
|
||||
});
|
||||
} finally {
|
||||
await server.stop();
|
||||
await RemoteImagesTestUtils.triggerCleanup();
|
||||
await RemoteImagesTestUtils.wipeCache();
|
||||
sandbox.restore();
|
||||
client.verifySignatures = true;
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_remoteImages_prefetch() {
|
||||
const { AboutRobots } = RemoteImagesTestUtils.images;
|
||||
const sandbox = sinon.createSandbox();
|
||||
|
||||
sandbox.stub(RemoteSettingsExperimentLoader, "setTimer");
|
||||
sandbox.stub(RemoteSettingsExperimentLoader, "updateRecipes").resolves();
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["app.shield.optoutstudies.enabled", true],
|
||||
["datareporting.healthreport.uploadEnabled", true],
|
||||
[
|
||||
"browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments",
|
||||
`{"id":"messaging-experiments","enabled":true,"type":"remote-experiments","updateCycleInMs":0}`,
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
const stop = await RemoteImagesTestUtils.serveRemoteImages(AboutRobots);
|
||||
|
||||
const message = await PanelTestProvider.getMessages().then(msgs =>
|
||||
msgs.find(m => m.id === "SPOTLIGHT_MESSAGE_93")
|
||||
);
|
||||
message.content.logo = { imageId: AboutRobots.recordId };
|
||||
const recipe = ExperimentFakes.recipe("spotlight-test", {
|
||||
branches: [
|
||||
{
|
||||
slug: "snail",
|
||||
ratio: 1,
|
||||
features: [
|
||||
{
|
||||
featureId: "spotlight",
|
||||
value: message,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
bucketConfig: {
|
||||
start: 0,
|
||||
count: 100,
|
||||
total: 100,
|
||||
namespace: "mochitest",
|
||||
randomizationUnit: "normandy_id",
|
||||
},
|
||||
});
|
||||
|
||||
Assert.ok(ASRouter.initialized, "ASRouter should be initialized");
|
||||
|
||||
const prefetchFinished = BrowserUtils.promiseObserved(
|
||||
PREFETCH_FINISHED_TOPIC
|
||||
);
|
||||
|
||||
const {
|
||||
enrollmentPromise,
|
||||
doExperimentCleanup,
|
||||
} = ExperimentFakes.enrollmentHelper(recipe);
|
||||
|
||||
await Promise.all([enrollmentPromise, prefetchFinished]);
|
||||
|
||||
try {
|
||||
await RemoteImages.withDb(async db => {
|
||||
const entry = db.data.images[AboutRobots.recordId];
|
||||
|
||||
Assert.equal(
|
||||
entry.recordId,
|
||||
AboutRobots.recordId,
|
||||
"Prefetched image DB entry should exist"
|
||||
);
|
||||
Assert.equal(
|
||||
entry.mimetype,
|
||||
AboutRobots.mimetype,
|
||||
"Prefetched image should have correct mimetype"
|
||||
);
|
||||
Assert.equal(
|
||||
entry.hash,
|
||||
AboutRobots.hash,
|
||||
"Prefetched image should have correct hash"
|
||||
);
|
||||
});
|
||||
|
||||
const path = PathUtils.join(REMOTE_IMAGES_PATH, AboutRobots.recordId);
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => IOUtils.exists(path),
|
||||
"Prefetched image should be written to disk"
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
await IOUtils.computeHexDigest(path, "sha256"),
|
||||
AboutRobots.hash,
|
||||
"AboutRobots image should have correct hash"
|
||||
);
|
||||
} finally {
|
||||
await doExperimentCleanup();
|
||||
await stop();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
await ASRouter._updateMessageProviders();
|
||||
await RemoteImagesTestUtils.wipeCache();
|
||||
sandbox.reset();
|
||||
}
|
||||
});
|
||||
|
@ -13,8 +13,7 @@ from buildconfig import substs
|
||||
|
||||
"""
|
||||
Scans the given directories for binaries referencing the AddressSanitizer
|
||||
runtime library, copies it to the main directory and rewrites binaries to not
|
||||
reference it with absolute paths but with @executable_path instead.
|
||||
runtime library, copies it to the main directory.
|
||||
"""
|
||||
|
||||
# This is the dylib name pattern
|
||||
@ -83,10 +82,6 @@ def scan_directory(path):
|
||||
dylibName = match.group(0)
|
||||
absDylibPath = line.split()[0]
|
||||
|
||||
# Don't try to rewrite binaries twice
|
||||
if absDylibPath.startswith("@executable_path/"):
|
||||
continue
|
||||
|
||||
dylibsRequired.add(dylibName)
|
||||
|
||||
if dylibName not in dylibsCopied:
|
||||
@ -100,16 +95,6 @@ def scan_directory(path):
|
||||
# Copy the runtime once to the main directory, which is passed
|
||||
# as the argument to this function.
|
||||
shutil.copy(copyDylibPath, str(path))
|
||||
|
||||
# Now rewrite the library itself
|
||||
subprocess.check_call(
|
||||
[
|
||||
substs["INSTALL_NAME_TOOL"],
|
||||
"-id",
|
||||
f"@executable_path/{dylibName}",
|
||||
str(path / dylibName),
|
||||
]
|
||||
)
|
||||
dylibsCopied.add(dylibName)
|
||||
else:
|
||||
print(
|
||||
@ -117,20 +102,6 @@ def scan_directory(path):
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
# Now use install_name_tool to rewrite the path in our binary
|
||||
if file.parent == path:
|
||||
relpath = ""
|
||||
else:
|
||||
relpath = f"{os.path.relpath(str(path), str(file.parent))}/"
|
||||
subprocess.check_call(
|
||||
[
|
||||
substs["INSTALL_NAME_TOOL"],
|
||||
"-change",
|
||||
absDylibPath,
|
||||
f"@executable_path/{relpath}{dylibName}",
|
||||
str(file),
|
||||
]
|
||||
)
|
||||
break
|
||||
|
||||
dylibsMissing = dylibsRequired - dylibsCopied
|
||||
|
@ -58,7 +58,7 @@ impl MyObserver {
|
||||
&self,
|
||||
_subject: *const nsISupports,
|
||||
_topic: *const c_char,
|
||||
_data: *const i16,
|
||||
_data: *const u16,
|
||||
) -> nsresult {
|
||||
self.ran.store(true, Ordering::SeqCst);
|
||||
nserror::NS_OK
|
||||
|
@ -528,6 +528,11 @@ already_AddRefed<PerformanceMeasure> Performance::Measure(
|
||||
JSContext* aCx, const nsAString& aName,
|
||||
const StringOrPerformanceMeasureOptions& aStartOrMeasureOptions,
|
||||
const Optional<nsAString>& aEndMark, ErrorResult& aRv) {
|
||||
if (!GetParentObject()) {
|
||||
aRv.ThrowInvalidStateError("Global object is unavailable");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// When resisting fingerprinting, we don't add marks to the buffer. Since
|
||||
// measure relies on relationships between marks in the buffer, this method
|
||||
// will throw if we look for user-entered marks so we return a dummy measure
|
||||
|
@ -40,13 +40,17 @@
|
||||
ok(true, 'new PerformanceMark() on dying global did not crash');
|
||||
|
||||
try {
|
||||
dyingWindow.performance.mark('markMethod', {detail: 'markMethodDetail'});
|
||||
dyingWindow.performance.mark('markMethod', {detail: 'markMethodDetail'});
|
||||
} catch (e) {
|
||||
is(e.code, e.INVALID_STATE_ERR, 'performance.mark on dying global threw expected exception');
|
||||
is(e.code, e.INVALID_STATE_ERR, 'performance.mark on dying global threw expected exception');
|
||||
}
|
||||
ok(true, 'performance.mark on dying global did not crash');
|
||||
|
||||
dyingWindow.performance.measure('measureMethod');
|
||||
try {
|
||||
dyingWindow.performance.measure('measureMethod');
|
||||
} catch (e) {
|
||||
is(e.code, e.INVALID_STATE_ERR, 'performance.measure on dying global threw expected exception');
|
||||
}
|
||||
ok(true, 'performance.measure on dying global did not crash');
|
||||
}
|
||||
</script>
|
||||
|
@ -585,8 +585,6 @@ MSG_DEF(JSMSG_UNDEFINED_UNIT, 0, JSEXN_TYPEERR, "undefined unit in Numb
|
||||
MSG_DEF(JSMSG_UNDEFINED_DATE, 2, JSEXN_TYPEERR, "undefined {0}-date in DateTimeFormat.{1}()")
|
||||
MSG_DEF(JSMSG_UNDEFINED_NUMBER, 3, JSEXN_TYPEERR, "undefined {0} number in {1}.{2}()")
|
||||
MSG_DEF(JSMSG_UNDEFINED_TYPE, 0, JSEXN_TYPEERR, "missing \"type\" option in DisplayNames()")
|
||||
MSG_DEF(JSMSG_START_AFTER_END_DATE, 1, JSEXN_RANGEERR, "start-date after end-date in DateTimeFormat.{0}()")
|
||||
MSG_DEF(JSMSG_START_AFTER_END_NUMBER, 2, JSEXN_RANGEERR, "start number after end number in {0}.{1}()")
|
||||
MSG_DEF(JSMSG_EXPONENT_TOO_LARGE, 0, JSEXN_RANGEERR, "exponent is too large")
|
||||
MSG_DEF(JSMSG_NAN_NUMBER_RANGE, 3, JSEXN_RANGEERR, "range can't {0} with NaN in {1}.{2}()")
|
||||
MSG_DEF(JSMSG_INVALID_NUMBER_OPTION, 2, JSEXN_TYPEERR, "can't set option {0} when {1} is used")
|
||||
|
@ -1407,7 +1407,6 @@ static bool PartitionDateTimeRangePattern(
|
||||
ClippedTime y, bool* equal) {
|
||||
MOZ_ASSERT(x.isValid());
|
||||
MOZ_ASSERT(y.isValid());
|
||||
MOZ_ASSERT(x.toDouble() <= y.toDouble());
|
||||
|
||||
// We can't access the calendar used by UDateIntervalFormat to change it to a
|
||||
// proleptic Gregorian calendar. Instead we need to call a different formatter
|
||||
@ -1424,7 +1423,8 @@ static bool PartitionDateTimeRangePattern(
|
||||
GregorianChangeDate + msPerDay;
|
||||
|
||||
mozilla::intl::ICUResult result = Ok();
|
||||
if (x.toDouble() < GregorianChangeDatePlusOneDay) {
|
||||
if (x.toDouble() < GregorianChangeDatePlusOneDay ||
|
||||
y.toDouble() < GregorianChangeDatePlusOneDay) {
|
||||
// Create calendar objects for the start and end date by cloning the date
|
||||
// formatter calendar. The date formatter calendar already has the correct
|
||||
// time zone set and was changed to use a proleptic Gregorian calendar.
|
||||
@ -1565,10 +1565,6 @@ bool js::intl_FormatDateTimeRange(JSContext* cx, unsigned argc, Value* vp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Self-hosted code should have checked this condition.
|
||||
MOZ_ASSERT(x.toDouble() <= y.toDouble(),
|
||||
"start date mustn't be after the end date");
|
||||
|
||||
mozilla::intl::DateTimeFormat* df =
|
||||
GetOrCreateDateTimeFormat(cx, dateTimeFormat);
|
||||
if (!df) {
|
||||
|
@ -667,33 +667,28 @@ function Intl_DateTimeFormat_formatRange(startDate, endDate) {
|
||||
// Step 1.
|
||||
var dtf = this;
|
||||
|
||||
// Steps 2-3.
|
||||
// Step 2.
|
||||
if (!IsObject(dtf) || (dtf = intl_GuardToDateTimeFormat(dtf)) === null) {
|
||||
return callFunction(intl_CallDateTimeFormatMethodIfWrapped, this, startDate, endDate,
|
||||
"Intl_DateTimeFormat_formatRange");
|
||||
}
|
||||
|
||||
// Step 4.
|
||||
// Step 3.
|
||||
if (startDate === undefined || endDate === undefined) {
|
||||
ThrowTypeError(JSMSG_UNDEFINED_DATE, startDate === undefined ? "start" : "end",
|
||||
"formatRange");
|
||||
}
|
||||
|
||||
// Step 5.
|
||||
// Step 4.
|
||||
var x = ToNumber(startDate);
|
||||
|
||||
// Step 6.
|
||||
// Step 5.
|
||||
var y = ToNumber(endDate);
|
||||
|
||||
// Step 7.
|
||||
if (x > y) {
|
||||
ThrowRangeError(JSMSG_START_AFTER_END_DATE, "formatRange");
|
||||
}
|
||||
|
||||
// Ensure the DateTimeFormat internals are resolved.
|
||||
getDateTimeFormatInternals(dtf);
|
||||
|
||||
// Step 8.
|
||||
// Step 6.
|
||||
return intl_FormatDateTimeRange(dtf, x, y, /* formatToParts = */ false);
|
||||
}
|
||||
|
||||
@ -706,33 +701,28 @@ function Intl_DateTimeFormat_formatRangeToParts(startDate, endDate) {
|
||||
// Step 1.
|
||||
var dtf = this;
|
||||
|
||||
// Steps 2-3.
|
||||
// Step 2.
|
||||
if (!IsObject(dtf) || (dtf = intl_GuardToDateTimeFormat(dtf)) === null) {
|
||||
return callFunction(intl_CallDateTimeFormatMethodIfWrapped, this, startDate, endDate,
|
||||
"Intl_DateTimeFormat_formatRangeToParts");
|
||||
}
|
||||
|
||||
// Step 4.
|
||||
// Step 3.
|
||||
if (startDate === undefined || endDate === undefined) {
|
||||
ThrowTypeError(JSMSG_UNDEFINED_DATE, startDate === undefined ? "start" : "end",
|
||||
"formatRangeToParts");
|
||||
}
|
||||
|
||||
// Step 5.
|
||||
// Step 4.
|
||||
var x = ToNumber(startDate);
|
||||
|
||||
// Step 6.
|
||||
// Step 5.
|
||||
var y = ToNumber(endDate);
|
||||
|
||||
// Step 7.
|
||||
if (x > y) {
|
||||
ThrowRangeError(JSMSG_START_AFTER_END_DATE, "formatRangeToParts");
|
||||
}
|
||||
|
||||
// Ensure the DateTimeFormat internals are resolved.
|
||||
getDateTimeFormatInternals(dtf);
|
||||
|
||||
// Step 8.
|
||||
// Step 6.
|
||||
return intl_FormatDateTimeRange(dtf, x, y, /* formatToParts = */ true);
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,9 @@ namespace js::intl {
|
||||
* Note: Internally we leave the decimal point where it lies to avoid copying
|
||||
* the string, but otherwise ignore it once we calculate the normalized
|
||||
* exponent.
|
||||
*
|
||||
* TODO: Remove unused capabilities once there's a concrete PR for
|
||||
* <https://github.com/tc39/proposal-intl-numberformat-v3/issues/98>.
|
||||
*/
|
||||
class MOZ_STACK_CLASS DecimalNumber final {
|
||||
using Latin1String = mozilla::Span<const JS::Latin1Char>;
|
||||
|
@ -979,8 +979,7 @@ static bool IsNonDecimalNumber(JSLinearString* str) {
|
||||
: IsNonDecimalNumber(str->twoByteRange(nogc));
|
||||
}
|
||||
|
||||
static bool ToIntlMathematicalValue(JSContext* cx, MutableHandleValue value,
|
||||
double* numberApproximation = nullptr) {
|
||||
static bool ToIntlMathematicalValue(JSContext* cx, MutableHandleValue value) {
|
||||
if (!ToPrimitive(cx, JSTYPE_NUMBER, value)) {
|
||||
return false;
|
||||
}
|
||||
@ -1026,9 +1025,6 @@ static bool ToIntlMathematicalValue(JSContext* cx, MutableHandleValue value,
|
||||
|
||||
// Parse the string as a number.
|
||||
double number = LinearStringToNumber(str);
|
||||
if (numberApproximation) {
|
||||
*numberApproximation = number;
|
||||
}
|
||||
|
||||
bool exponentTooLarge = false;
|
||||
if (mozilla::IsNaN(number)) {
|
||||
@ -1256,207 +1252,6 @@ static JSLinearString* ToLinearString(JSContext* cx, HandleValue val) {
|
||||
return str ? str->ensureLinear(cx) : nullptr;
|
||||
};
|
||||
|
||||
static bool ValidateNumberRange(JSContext* cx, MutableHandleValue start,
|
||||
double startApprox, MutableHandleValue end,
|
||||
double endApprox, bool formatToParts) {
|
||||
static auto isSpecificDouble = [](const Value& val, auto fn) {
|
||||
return val.isDouble() && fn(val.toDouble());
|
||||
};
|
||||
|
||||
static auto isNaN = [](const Value& val) {
|
||||
return isSpecificDouble(val, mozilla::IsNaN<double>);
|
||||
};
|
||||
|
||||
static auto isPositiveInfinity = [](const Value& val) {
|
||||
return isSpecificDouble(
|
||||
val, [](double num) { return num > 0 && mozilla::IsInfinite(num); });
|
||||
};
|
||||
|
||||
static auto isNegativeInfinity = [](const Value& val) {
|
||||
return isSpecificDouble(
|
||||
val, [](double num) { return num < 0 && mozilla::IsInfinite(num); });
|
||||
};
|
||||
|
||||
static auto isNegativeZero = [](const Value& val) {
|
||||
return isSpecificDouble(val, mozilla::IsNegativeZero<double>);
|
||||
};
|
||||
|
||||
static auto isMathematicalValue = [](const Value& val) {
|
||||
// |ToIntlMathematicalValue()| normalizes non-finite values and negative
|
||||
// zero to Double values, so any string is guaranteed to be a mathematical
|
||||
// value at this point.
|
||||
if (!val.isDouble()) {
|
||||
return true;
|
||||
}
|
||||
double num = val.toDouble();
|
||||
return mozilla::IsFinite(num) && !mozilla::IsNegativeZero(num);
|
||||
};
|
||||
|
||||
static auto isPositiveOrZero = [](const Value& val, double approx) {
|
||||
MOZ_ASSERT(isMathematicalValue(val));
|
||||
|
||||
if (val.isNumber()) {
|
||||
return val.toNumber() >= 0;
|
||||
}
|
||||
if (val.isBigInt()) {
|
||||
return !val.toBigInt()->isNegative();
|
||||
}
|
||||
return approx >= 0;
|
||||
};
|
||||
|
||||
auto throwRangeError = [&]() {
|
||||
JS_ReportErrorNumberASCII(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_START_AFTER_END_NUMBER,
|
||||
"NumberFormat", formatToParts ? "formatRangeToParts" : "formatRange");
|
||||
return false;
|
||||
};
|
||||
|
||||
// PartitionNumberRangePattern, step 1.
|
||||
if (isNaN(start)) {
|
||||
JS_ReportErrorNumberASCII(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_NAN_NUMBER_RANGE, "start",
|
||||
"NumberFormat", formatToParts ? "formatRangeToParts" : "formatRange");
|
||||
return false;
|
||||
}
|
||||
if (isNaN(end)) {
|
||||
JS_ReportErrorNumberASCII(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_NAN_NUMBER_RANGE, "end",
|
||||
"NumberFormat", formatToParts ? "formatRangeToParts" : "formatRange");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure |start| and |end| can be correctly classified.
|
||||
MOZ_ASSERT(isMathematicalValue(start) || isNegativeZero(start) ||
|
||||
isNegativeInfinity(start) || isPositiveInfinity(start));
|
||||
MOZ_ASSERT(isMathematicalValue(end) || isNegativeZero(end) ||
|
||||
isNegativeInfinity(end) || isPositiveInfinity(end));
|
||||
|
||||
// PartitionNumberRangePattern, step 2.
|
||||
if (isMathematicalValue(start)) {
|
||||
// PartitionNumberRangePattern, step 2.a.
|
||||
if (isMathematicalValue(end)) {
|
||||
if (!start.isString() && !end.isString()) {
|
||||
MOZ_ASSERT(start.isNumeric() && end.isNumeric());
|
||||
|
||||
bool isLessThan;
|
||||
if (!LessThan(cx, end, start, &isLessThan)) {
|
||||
return false;
|
||||
}
|
||||
if (isLessThan) {
|
||||
return throwRangeError();
|
||||
}
|
||||
} else {
|
||||
// |startApprox| and |endApprox| are only initially computed for string
|
||||
// numbers.
|
||||
if (start.isNumber()) {
|
||||
startApprox = start.toNumber();
|
||||
} else if (start.isBigInt()) {
|
||||
startApprox = BigInt::numberValue(start.toBigInt());
|
||||
}
|
||||
if (end.isNumber()) {
|
||||
endApprox = end.toNumber();
|
||||
} else if (end.isBigInt()) {
|
||||
endApprox = BigInt::numberValue(end.toBigInt());
|
||||
}
|
||||
|
||||
// If the approximation is smaller, the actual value is definitely
|
||||
// smaller, too.
|
||||
if (endApprox < startApprox) {
|
||||
return throwRangeError();
|
||||
}
|
||||
|
||||
// If both approximations are equal to each other, we have to perform
|
||||
// more work.
|
||||
if (endApprox == startApprox) {
|
||||
Rooted<JSLinearString*> strStart(cx, ToLinearString(cx, start));
|
||||
if (!strStart) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<JSLinearString*> strEnd(cx, ToLinearString(cx, end));
|
||||
if (!strEnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool endLessThanStart;
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
|
||||
auto decStart = intl::DecimalNumber::from(strStart, nogc);
|
||||
MOZ_ASSERT(decStart);
|
||||
|
||||
auto decEnd = intl::DecimalNumber::from(strEnd, nogc);
|
||||
MOZ_ASSERT(decEnd);
|
||||
|
||||
endLessThanStart = decEnd->compareTo(*decStart) < 0;
|
||||
}
|
||||
if (endLessThanStart) {
|
||||
return throwRangeError();
|
||||
}
|
||||
|
||||
// If either value is a string, we end up passing both values as
|
||||
// strings to the formatter. So let's save the string representation
|
||||
// here, because then we don't have to recompute them later on.
|
||||
start.setString(strStart);
|
||||
end.setString(strEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PartitionNumberRangePattern, step 2.b.
|
||||
else if (isNegativeInfinity(end)) {
|
||||
return throwRangeError();
|
||||
}
|
||||
|
||||
// PartitionNumberRangePattern, step 2.c.
|
||||
else if (isNegativeZero(end)) {
|
||||
if (isPositiveOrZero(start, startApprox)) {
|
||||
return throwRangeError();
|
||||
}
|
||||
}
|
||||
|
||||
// No range restrictions when the end is positive infinity.
|
||||
else {
|
||||
MOZ_ASSERT(isPositiveInfinity(end));
|
||||
}
|
||||
}
|
||||
|
||||
// PartitionNumberRangePattern, step 3.
|
||||
else if (isPositiveInfinity(start)) {
|
||||
// PartitionNumberRangePattern, steps 3.a-c.
|
||||
if (!isPositiveInfinity(end)) {
|
||||
return throwRangeError();
|
||||
}
|
||||
}
|
||||
|
||||
// PartitionNumberRangePattern, step 4.
|
||||
else if (isNegativeZero(start)) {
|
||||
// PartitionNumberRangePattern, step 4.a.
|
||||
if (isMathematicalValue(end)) {
|
||||
if (!isPositiveOrZero(end, endApprox)) {
|
||||
return throwRangeError();
|
||||
}
|
||||
}
|
||||
|
||||
// PartitionNumberRangePattern, step 4.b.
|
||||
else if (isNegativeInfinity(end)) {
|
||||
return throwRangeError();
|
||||
}
|
||||
|
||||
// No range restrictions when the end is negative zero or positive infinity.
|
||||
else {
|
||||
MOZ_ASSERT(isNegativeZero(end) || isPositiveInfinity(end));
|
||||
}
|
||||
}
|
||||
|
||||
// No range restrictions when the start is negative infinity.
|
||||
else {
|
||||
MOZ_ASSERT(isNegativeInfinity(start));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool js::intl_FormatNumberRange(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 4);
|
||||
@ -1470,19 +1265,26 @@ bool js::intl_FormatNumberRange(JSContext* cx, unsigned argc, Value* vp) {
|
||||
bool formatToParts = args[3].toBoolean();
|
||||
|
||||
RootedValue start(cx, args[1]);
|
||||
double startApprox = mozilla::UnspecifiedNaN<double>();
|
||||
if (!ToIntlMathematicalValue(cx, &start, &startApprox)) {
|
||||
if (!ToIntlMathematicalValue(cx, &start)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue end(cx, args[2]);
|
||||
double endApprox = mozilla::UnspecifiedNaN<double>();
|
||||
if (!ToIntlMathematicalValue(cx, &end, &endApprox)) {
|
||||
if (!ToIntlMathematicalValue(cx, &end)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateNumberRange(cx, &start, startApprox, &end, endApprox,
|
||||
formatToParts)) {
|
||||
// PartitionNumberRangePattern, step 1.
|
||||
if (start.isDouble() && mozilla::IsNaN(start.toDouble())) {
|
||||
JS_ReportErrorNumberASCII(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_NAN_NUMBER_RANGE, "start",
|
||||
"NumberFormat", formatToParts ? "formatRangeToParts" : "formatRange");
|
||||
return false;
|
||||
}
|
||||
if (end.isDouble() && mozilla::IsNaN(end.toDouble())) {
|
||||
JS_ReportErrorNumberASCII(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_NAN_NUMBER_RANGE, "end",
|
||||
"NumberFormat", formatToParts ? "formatRangeToParts" : "formatRange");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -365,21 +365,13 @@ bool js::intl_SelectPluralRuleRange(JSContext* cx, unsigned argc, Value* vp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 6.
|
||||
if (x > y) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_START_AFTER_END_NUMBER, "PluralRules",
|
||||
"selectRange");
|
||||
return false;
|
||||
}
|
||||
|
||||
using PluralRules = mozilla::intl::PluralRules;
|
||||
PluralRules* pr = GetOrCreatePluralRules(cx, pluralRules);
|
||||
if (!pr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Steps 7-11.
|
||||
// Steps 6-10.
|
||||
auto keywordResult = pr->SelectRange(x, y);
|
||||
if (keywordResult.isErr()) {
|
||||
intl::ReportInternalError(cx, keywordResult.unwrapErr());
|
||||
|
@ -1038,12 +1038,7 @@ void MacroAssembler::assertStackAlignment(uint32_t alignment,
|
||||
}
|
||||
|
||||
void MacroAssembler::storeCallBoolResult(Register reg) {
|
||||
if (reg != ReturnReg) {
|
||||
mov(ReturnReg, reg);
|
||||
}
|
||||
// C++ compilers like to only use the bottom byte for bools, but we
|
||||
// need to maintain the entire register.
|
||||
and32(Imm32(0xFF), reg);
|
||||
convertBoolToInt32(ReturnReg, reg);
|
||||
}
|
||||
|
||||
void MacroAssembler::storeCallInt32Result(Register reg) {
|
||||
|
@ -1,16 +1,23 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty("Intl")||release_or_beta)
|
||||
|
||||
// String representation for Number.MAX_VALUE.
|
||||
const en_Number_MAX_VALUE = "179,769,313,486,231,570" + ",000".repeat(97);
|
||||
const de_Number_MAX_VALUE = en_Number_MAX_VALUE.replaceAll(",", ".");
|
||||
const fr_Number_MAX_VALUE = en_Number_MAX_VALUE.replaceAll(",", " ");
|
||||
|
||||
const tests = {
|
||||
"en": {
|
||||
options: {},
|
||||
ranges: [
|
||||
// Values around zero.
|
||||
{start: 0, end: 0, result: "~0"},
|
||||
{start: 0, end: -0, result: "0–-0"},
|
||||
{start: -0, end: 0, result: "-0 – 0"},
|
||||
{start: -0, end: 0.1e-3, result: "-0 – 0"},
|
||||
{start: -0, end: "0.1e-3", result: "-0 – 0"},
|
||||
{start: "-0", end: 0.1e-3, result: "-0 – 0"},
|
||||
{start: -0, end: -0, result: "~-0"},
|
||||
{start: -0, end: -0.1, result: "-0 – -0.1"},
|
||||
|
||||
// Values starting at negative infinity.
|
||||
{start: -Infinity, end: -Infinity, result: "~-∞"},
|
||||
@ -18,6 +25,19 @@ const tests = {
|
||||
{start: -Infinity, end: +0, result: "-∞ – 0"},
|
||||
{start: -Infinity, end: +Infinity, result: "-∞ – ∞"},
|
||||
|
||||
// Values ending at negative infinity.
|
||||
{start: -Number.MAX_VALUE, end: -Infinity, result: "-" + en_Number_MAX_VALUE + " – -∞"},
|
||||
{start: -0, end: -Infinity, result: "-0 – -∞"},
|
||||
{start: 0, end: -Infinity, result: "0–-∞"},
|
||||
{start: Number.MAX_VALUE, end: -Infinity, result: en_Number_MAX_VALUE + "–-∞"},
|
||||
|
||||
// Values starting at positive infinity.
|
||||
{start: Infinity, end: Number.MAX_VALUE, result: "∞–" + en_Number_MAX_VALUE},
|
||||
{start: Infinity, end: 0, result: "∞–0"},
|
||||
{start: Infinity, end: -0, result: "∞–-0"},
|
||||
{start: Infinity, end: -Number.MAX_VALUE, result: "∞–-" + en_Number_MAX_VALUE},
|
||||
{start: Infinity, end: -Infinity, result: "∞–-∞"},
|
||||
|
||||
// Values ending at positive infinity.
|
||||
{start: Infinity, end: Infinity, result: "~∞"},
|
||||
|
||||
@ -37,6 +57,26 @@ const tests = {
|
||||
end: "9007199254740993",
|
||||
result: "9,007,199,254,740,991–9,007,199,254,740,993",
|
||||
},
|
||||
|
||||
// Start value is larger than end value.
|
||||
{start: -0, end: -0.1, result: "-0 – -0.1"},
|
||||
{start: -0, end: -Number.MAX_VALUE, result: "-0 – -" + en_Number_MAX_VALUE},
|
||||
{start: 1, end: 0, result: "1–0"},
|
||||
{start: 0, end: -1, result: "0–-1"},
|
||||
{start: 1, end: -1, result: "1–-1"},
|
||||
{start: -1, end: -2, result: "-1 – -2"},
|
||||
{start: "10e2", end: "1e-3", result: "1,000–0.001"},
|
||||
{start: "0x100", end: "1e1", result: "256–10"},
|
||||
{start: ".1e-999999", end: ".01e-999999", result: "~0"},
|
||||
{start: ".1e99999", end: "0", result: "100" + ",000".repeat(33332) + "–0"},
|
||||
// Number.MAX_VALUE is 1.7976931348623157e+308.
|
||||
{
|
||||
start: "1.7976931348623158e+308",
|
||||
end: Number.MAX_VALUE,
|
||||
result: "179,769,313,486,231,580" + ",000".repeat(97) + "–" + en_Number_MAX_VALUE,
|
||||
},
|
||||
// Number.MIN_VALUE is 5e-324.
|
||||
{start: "6e-324", end: Number.MIN_VALUE, result: "~0"},
|
||||
],
|
||||
},
|
||||
"de": {
|
||||
@ -44,11 +84,13 @@ const tests = {
|
||||
ranges: [
|
||||
// Values around zero.
|
||||
{start: 0, end: 0, result: "≈0,00 €"},
|
||||
{start: 0, end: -0, result: "0,00 € – -0,00 €"},
|
||||
{start: -0, end: 0, result: "-0,00 € – 0,00 €"},
|
||||
{start: -0, end: 0.1e-3, result: "-0,00 € – 0,00 €"},
|
||||
{start: -0, end: "0.1e-3", result: "-0,00 € – 0,00 €"},
|
||||
{start: "-0", end: 0.1e-3, result: "-0,00 € – 0,00 €"},
|
||||
{start: -0, end: -0, result: "≈-0,00 €"},
|
||||
{start: -0, end: -0.1, result: "-0,00–0,10 €"},
|
||||
|
||||
// Values starting at negative infinity.
|
||||
{start: -Infinity, end: -Infinity, result: "≈-∞ €"},
|
||||
@ -56,6 +98,19 @@ const tests = {
|
||||
{start: -Infinity, end: +0, result: "-∞ € – 0,00 €"},
|
||||
{start: -Infinity, end: +Infinity, result: "-∞ € – ∞ €"},
|
||||
|
||||
// Values ending at negative infinity.
|
||||
{start: -Number.MAX_VALUE, end: -Infinity, result: "-" + de_Number_MAX_VALUE + ",00–∞ €"},
|
||||
{start: -0, end: -Infinity, result: "-0,00–∞ €"},
|
||||
{start: 0, end: -Infinity, result: "0,00 € – -∞ €"},
|
||||
{start: Number.MAX_VALUE, end: -Infinity, result: de_Number_MAX_VALUE + ",00 € – -∞ €"},
|
||||
|
||||
// Values starting at positive infinity.
|
||||
{start: Infinity, end: Number.MAX_VALUE, result: "∞–" + de_Number_MAX_VALUE + ",00 €"},
|
||||
{start: Infinity, end: 0, result: "∞–0,00 €"},
|
||||
{start: Infinity, end: -0, result: "∞ € – -0,00 €"},
|
||||
{start: Infinity, end: -Number.MAX_VALUE, result: "∞ € – -" + de_Number_MAX_VALUE + ",00 €"},
|
||||
{start: Infinity, end: -Infinity, result: "∞ € – -∞ €"},
|
||||
|
||||
// Values ending at positive infinity.
|
||||
{start: Infinity, end: Infinity, result: "≈∞ €"},
|
||||
|
||||
@ -75,6 +130,26 @@ const tests = {
|
||||
end: "9007199254740993",
|
||||
result: "9.007.199.254.740.991,00–9.007.199.254.740.993,00 €",
|
||||
},
|
||||
|
||||
// Start value is larger than end value.
|
||||
{start: -0, end: -0.1, result: "-0,00–0,10 €"},
|
||||
{start: -0, end: -Number.MAX_VALUE, result: "-0,00–" + de_Number_MAX_VALUE + ",00 €"},
|
||||
{start: 1, end: 0, result: "1,00–0,00 €"},
|
||||
{start: 0, end: -1, result: "0,00 € – -1,00 €"},
|
||||
{start: 1, end: -1, result: "1,00 € – -1,00 €"},
|
||||
{start: -1, end: -2, result: "-1,00–2,00 €"},
|
||||
{start: "10e2", end: "1e-3", result: "1.000,00–0,00 €"},
|
||||
{start: "0x100", end: "1e1", result: "256,00–10,00 €"},
|
||||
{start: ".1e-999999", end: ".01e-999999", result: "≈0,00 €"},
|
||||
{start: ".1e99999", end: "0", result: "100" + ".000".repeat(33332) + ",00–0,00 €"},
|
||||
// Number.MAX_VALUE is 1.7976931348623157e+308.
|
||||
{
|
||||
start: "1.7976931348623158e+308",
|
||||
end: Number.MAX_VALUE,
|
||||
result: "179.769.313.486.231.580" + ".000".repeat(97) + ",00–" + de_Number_MAX_VALUE + ",00 €",
|
||||
},
|
||||
// Number.MIN_VALUE is 5e-324.
|
||||
{start: "6e-324", end: Number.MIN_VALUE, result: "≈0,00 €"},
|
||||
],
|
||||
},
|
||||
"fr": {
|
||||
@ -83,10 +158,12 @@ const tests = {
|
||||
// Values around zero.
|
||||
{start: 0, end: 0, result: "≃0 m"},
|
||||
{start: -0, end: 0, result: "-0 – 0 m"},
|
||||
{start: -0, end: 0, result: "-0 – 0 m"},
|
||||
{start: -0, end: 0.1e-3, result: "-0 – 0 m"},
|
||||
{start: -0, end: "0.1e-3", result: "-0 – 0 m"},
|
||||
{start: "-0", end: 0.1e-3, result: "-0 – 0 m"},
|
||||
{start: -0, end: -0, result: "≃-0 m"},
|
||||
{start: -0, end: -0.1, result: "-0 – -0,1 m"},
|
||||
|
||||
// Values starting at negative infinity.
|
||||
{start: -Infinity, end: -Infinity, result: "≃-∞ m"},
|
||||
@ -94,6 +171,19 @@ const tests = {
|
||||
{start: -Infinity, end: +0, result: "-∞ – 0 m"},
|
||||
{start: -Infinity, end: +Infinity, result: "-∞ – ∞ m"},
|
||||
|
||||
// Values ending at negative infinity.
|
||||
{start: -Number.MAX_VALUE, end: -Infinity, result: "-" + fr_Number_MAX_VALUE + " – -∞ m"},
|
||||
{start: -0, end: -Infinity, result: "-0 – -∞ m"},
|
||||
{start: 0, end: -Infinity, result: "0–-∞ m"},
|
||||
{start: Number.MAX_VALUE, end: -Infinity, result: fr_Number_MAX_VALUE + "–-∞ m"},
|
||||
|
||||
// Values starting at positive infinity.
|
||||
{start: Infinity, end: Number.MAX_VALUE, result: "∞–" + fr_Number_MAX_VALUE + " m"},
|
||||
{start: Infinity, end: 0, result: "∞–0 m"},
|
||||
{start: Infinity, end: -0, result: "∞–-0 m"},
|
||||
{start: Infinity, end: -Number.MAX_VALUE, result: "∞–-" + fr_Number_MAX_VALUE + " m"},
|
||||
{start: Infinity, end: -Infinity, result: "∞–-∞ m"},
|
||||
|
||||
// Values ending at positive infinity.
|
||||
{start: Infinity, end: Infinity, result: "≃∞ m"},
|
||||
|
||||
@ -113,6 +203,26 @@ const tests = {
|
||||
end: "9007199254740993",
|
||||
result: "9 007 199 254 740 991–9 007 199 254 740 993 m",
|
||||
},
|
||||
|
||||
// Start value is larger than end value.
|
||||
{start: -0, end: -0.1, result: "-0 – -0,1 m"},
|
||||
{start: -0, end: -Number.MAX_VALUE, result: "-0 – -" + fr_Number_MAX_VALUE + " m"},
|
||||
{start: 1, end: 0, result: "1–0 m"},
|
||||
{start: 0, end: -1, result: "0–-1 m"},
|
||||
{start: 1, end: -1, result: "1–-1 m"},
|
||||
{start: -1, end: -2, result: "-1 – -2 m"},
|
||||
{start: "10e2", end: "1e-3", result: "1 000–0,001 m"},
|
||||
{start: "0x100", end: "1e1", result: "256–10 m"},
|
||||
{start: ".1e-999999", end: ".01e-999999", result: "≃0 m"},
|
||||
{start: ".1e99999", end: "0", result: "100" + " 000".repeat(33332) + "–0 m"},
|
||||
// Number.MAX_VALUE is 1.7976931348623157e+308.
|
||||
{
|
||||
start: "1.7976931348623158e+308",
|
||||
end: Number.MAX_VALUE,
|
||||
result: "179 769 313 486 231 580" + " 000".repeat(97) + "–" + fr_Number_MAX_VALUE + " m",
|
||||
},
|
||||
// Number.MIN_VALUE is 5e-324.
|
||||
{start: "6e-324", end: Number.MIN_VALUE, result: "≃0 m"},
|
||||
],
|
||||
},
|
||||
// Non-ASCII digits.
|
||||
@ -165,51 +275,14 @@ for (let [locale, {options, ranges}] of Object.entries(tests)) {
|
||||
}
|
||||
}
|
||||
|
||||
// Throws an error if either value is NaN.
|
||||
{
|
||||
const errorTests = [
|
||||
// Throws an error if either value is NaN.
|
||||
{start: NaN, end: NaN},
|
||||
{start: 0, end: NaN},
|
||||
{start: NaN, end: 0},
|
||||
{start: Infinity, end: NaN},
|
||||
{start: NaN, end: Infinity},
|
||||
|
||||
// Positive infinity is larger than any other value.
|
||||
{start: Infinity, end: Number.MAX_VALUE},
|
||||
{start: Infinity, end: 0},
|
||||
{start: Infinity, end: -0},
|
||||
{start: Infinity, end: -Number.MAX_VALUE},
|
||||
{start: Infinity, end: -Infinity},
|
||||
|
||||
// Negative infinity is smaller than any other value.
|
||||
{start: -Number.MAX_VALUE, end: -Infinity},
|
||||
{start: -0, end: -Infinity},
|
||||
{start: 0, end: -Infinity},
|
||||
{start: Number.MAX_VALUE, end: -Infinity},
|
||||
|
||||
// Negative zero is larger than any other negative value.
|
||||
{start: -0, end: -0.1},
|
||||
{start: -0, end: -Number.MAX_VALUE},
|
||||
{start: -0, end: -Infinity},
|
||||
|
||||
// When values are mathematical values, |start| mustn't be larger than |end|.
|
||||
{start: 1, end: 0},
|
||||
{start: 0, end: -1},
|
||||
{start: 1, end: -1},
|
||||
{start: -1, end: -2},
|
||||
|
||||
// Positive zero is larger than negative zero.
|
||||
{start: 0, end: -0},
|
||||
|
||||
// String cases require to parse and interpret the inputs.
|
||||
{start: "10e2", end: "1e-3"},
|
||||
{start: "0x100", end: "1e1"},
|
||||
{start: ".1e-999999", end: ".01e-999999"},
|
||||
{start: ".1e99999", end: "0"},
|
||||
// Number.MAX_VALUE is 1.7976931348623157e+308.
|
||||
{start: "1.7976931348623158e+308", end: Number.MAX_VALUE},
|
||||
// Number.MIN_VALUE is 5e-324.
|
||||
{start: "6e-324", end: Number.MIN_VALUE},
|
||||
];
|
||||
|
||||
let nf = new Intl.NumberFormat("en");
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
// Any combination returns "other" for "en-US".
|
||||
{
|
||||
let numbers = [0, 0.5, 1.2, 1.5, 1.7, -1, 1, "1", 123456789.123456789];
|
||||
let numbers = [0, 0.5, 1.2, 1.5, 1.7, -1, 1, "1", 123456789.123456789, Infinity, -Infinity];
|
||||
|
||||
const weirdCases = [
|
||||
NaN,
|
||||
@ -15,26 +15,10 @@
|
||||
let pr = new Intl.PluralRules("en-US", {type});
|
||||
for (let start of numbers) {
|
||||
for (let end of numbers) {
|
||||
if (start <= end) {
|
||||
assertEq(pr.selectRange(start, end), "other");
|
||||
} else {
|
||||
assertThrowsInstanceOf(() => pr.selectRange(start, end), RangeError);
|
||||
}
|
||||
assertEq(pr.selectRange(start, end), "other");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertThrowsInstanceOf(() => pr.selectRange(Infinity, 0), RangeError);
|
||||
assertEq(pr.selectRange(0, Infinity), "other");
|
||||
assertEq(pr.selectRange(Infinity, Infinity), "other");
|
||||
}
|
||||
|
||||
{
|
||||
assertEq(pr.selectRange(-Infinity, 0), "other");
|
||||
assertThrowsInstanceOf(() => pr.selectRange(0, -Infinity), RangeError);
|
||||
assertEq(pr.selectRange(-Infinity, -Infinity), "other");
|
||||
}
|
||||
|
||||
for (let c of weirdCases) {
|
||||
assertThrowsInstanceOf(() => pr.selectRange(c, 0), RangeError);
|
||||
assertThrowsInstanceOf(() => pr.selectRange(0, c), RangeError);
|
||||
|
@ -1,9 +1,13 @@
|
||||
commit a3040a5047694f37b793c4394fd9cfa591dd17c1
|
||||
Author: André Bargull <andre.bargull@gmail.com>
|
||||
Date: Tue Jul 5 12:48:26 2022 +0200
|
||||
commit e623dd7a1183b04d862baea22a4b133b1635cb95
|
||||
Author: Mathias Bynens <mathias@qiwi.be>
|
||||
Date: Tue Jul 26 19:42:06 2022 +0200
|
||||
|
||||
Import SpiderMonkey Temporal tests
|
||||
Add manually written tests for RegExp `v` flag proposal (#3614)
|
||||
|
||||
Temporal tests written for the SpiderMonkey implementation. Mostly
|
||||
covers edge cases around mathematical operations and regression tests
|
||||
for reported spec bugs.
|
||||
https://github.com/tc39/proposal-regexp-v-flag
|
||||
|
||||
Issue: #3496, https://github.com/tc39/proposal-regexp-v-flag/issues/52
|
||||
|
||||
Add more tests for the new RegExp `v` flag
|
||||
|
||||
Add test for combination of `u` and `v` flag
|
||||
|
@ -10,13 +10,24 @@ features: [Symbol.asyncIterator, async-iteration]
|
||||
---*/
|
||||
|
||||
async function* generator() {}
|
||||
var AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(generator.prototype))
|
||||
const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(generator.prototype))
|
||||
const getAsyncIterator = AsyncIteratorPrototype[Symbol.asyncIterator];
|
||||
|
||||
var thisValue = {};
|
||||
const thisValues = [
|
||||
{},
|
||||
Symbol(),
|
||||
4,
|
||||
4n,
|
||||
true,
|
||||
undefined,
|
||||
null,
|
||||
];
|
||||
|
||||
assert.sameValue(
|
||||
AsyncIteratorPrototype[Symbol.asyncIterator].call(thisValue),
|
||||
thisValue
|
||||
);
|
||||
for (const thisValue of thisValues) {
|
||||
assert.sameValue(
|
||||
getAsyncIterator.call(thisValue),
|
||||
thisValue
|
||||
);
|
||||
}
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
@ -1,21 +1,34 @@
|
||||
// Copyright (C) 2015 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
es6id: 25.1.2.1
|
||||
description: Descriptor for `name` property
|
||||
esid: sec-%iteratorprototype%-@@iterator
|
||||
description: Return value of @@iterator on IteratorPrototype
|
||||
info: |
|
||||
%IteratorPrototype% [ @@iterator ] ( )
|
||||
1. Return the this value.
|
||||
features: [Symbol.iterator]
|
||||
---*/
|
||||
|
||||
var IteratorPrototype = Object.getPrototypeOf(
|
||||
const IteratorPrototype = Object.getPrototypeOf(
|
||||
Object.getPrototypeOf([][Symbol.iterator]())
|
||||
);
|
||||
var thisValue = {};
|
||||
const getIterator = IteratorPrototype[Symbol.iterator];
|
||||
|
||||
assert.sameValue(
|
||||
IteratorPrototype[Symbol.iterator].call(thisValue),
|
||||
thisValue
|
||||
);
|
||||
const thisValues = [
|
||||
{},
|
||||
Symbol(),
|
||||
4,
|
||||
4n,
|
||||
true,
|
||||
undefined,
|
||||
null,
|
||||
];
|
||||
|
||||
for (const thisValue of thisValues) {
|
||||
assert.sameValue(
|
||||
getIterator.call(thisValue),
|
||||
thisValue
|
||||
);
|
||||
}
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
@ -1,3 +1,4 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2017 Aleksey Shvayka. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
@ -17,19 +18,22 @@ info: |
|
||||
11. If dotAll is true, append "s" as the last code unit of result.
|
||||
12. Let unicode be ToBoolean(? Get(R, "unicode")).
|
||||
13. If unicode is true, append "u" as the last code unit of result.
|
||||
14. Let sticky be ToBoolean(? Get(R, "sticky")).
|
||||
15. If sticky is true, append "y" as the last code unit of result.
|
||||
16. Return result.
|
||||
features: [regexp-dotall, regexp-match-indices]
|
||||
14. Let unicodeSets be ! ToBoolean(? Get(R, "unicodeSets")).
|
||||
15. If unicodeSets is true, append "v" as the last code unit of result.
|
||||
16. Let sticky be ToBoolean(? Get(R, "sticky")).
|
||||
17. If sticky is true, append "y" as the last code unit of result.
|
||||
18. Return result.
|
||||
features: [regexp-dotall, regexp-match-indices, regexp-v-flag]
|
||||
---*/
|
||||
|
||||
assert.sameValue(/./.flags, '', 'no flags');
|
||||
assert.sameValue(/./d.flags, 'd', 'hasIndices');
|
||||
assert.sameValue(/./g.flags, 'g', 'global');
|
||||
assert.sameValue(/./i.flags, 'i', 'ignoreCase');
|
||||
assert.sameValue(/./m.flags, 'm', 'multiline');
|
||||
assert.sameValue(/./s.flags, 's', 'dotAll');
|
||||
assert.sameValue(/./u.flags, 'u', 'unicode');
|
||||
assert.sameValue(/./v.flags, 'v', 'unicodeSets');
|
||||
assert.sameValue(/./y.flags, 'y', 'sticky');
|
||||
assert.sameValue(/./d.flags, 'd', 'hasIndices');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
0
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/browser.js
vendored
Normal file
0
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/browser.js
vendored
Normal file
32
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/cross-realm.js
vendored
Normal file
32
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/cross-realm.js
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2022 Mathias Bynens, Ron Buckton, and the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-get-regexp.prototype.unicodeSets
|
||||
description: RegExp#unicodeSets invoked on a cross-realm object
|
||||
info: |
|
||||
get RegExp.prototype.unicodeSets -> RegExpHasFlag
|
||||
|
||||
1. Let R be the this value.
|
||||
2. If Type(R) is not Object, throw a TypeError exception.
|
||||
3. If R does not have an [[OriginalFlags]] internal slot, then
|
||||
a. If SameValue(R, %RegExpPrototype%) is true, return undefined.
|
||||
b. Otherwise, throw a TypeError exception.
|
||||
features: [regexp-v-flag, cross-realm]
|
||||
---*/
|
||||
|
||||
var unicodeSets = Object.getOwnPropertyDescriptor(RegExp.prototype, 'unicodeSets').get;
|
||||
var other = $262.createRealm().global;
|
||||
var otherRegExpProto = other.RegExp.prototype;
|
||||
var otherRegExpGetter = Object.getOwnPropertyDescriptor(otherRegExpProto, 'unicodeSets').get;
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(otherRegExpProto);
|
||||
}, 'cross-realm RegExp.prototype');
|
||||
|
||||
assert.throws(other.TypeError, function() {
|
||||
otherRegExpGetter.call(RegExp.prototype);
|
||||
}, 'cross-realm RegExp.prototype getter method against primary realm RegExp.prototype');
|
||||
|
||||
reportCompare(0, 0);
|
37
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/length.js
vendored
Normal file
37
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/length.js
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2022 Mathias Bynens, Ron Buckton, and André Bargull. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-get-regexp.prototype.unicodeSets
|
||||
description: >
|
||||
get RegExp.prototype.unicodeSets.length is 0.
|
||||
info: |
|
||||
get RegExp.prototype.unicodeSets
|
||||
|
||||
17 ECMAScript Standard Built-in Objects:
|
||||
Every built-in Function object, including constructors, has a length
|
||||
property whose value is an integer. Unless otherwise specified, this
|
||||
value is equal to the largest number of named arguments shown in the
|
||||
subclause headings for the function description, including optional
|
||||
parameters. However, rest parameters shown using the form “...name”
|
||||
are not included in the default argument count.
|
||||
|
||||
Unless otherwise specified, the length property of a built-in Function
|
||||
object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
|
||||
[[Configurable]]: true }.
|
||||
includes: [propertyHelper.js]
|
||||
features: [regexp-v-flag]
|
||||
---*/
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(RegExp.prototype, "unicodeSets");
|
||||
|
||||
assert.sameValue(desc.get.length, 0);
|
||||
|
||||
verifyProperty(desc.get, "length", {
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
reportCompare(0, 0);
|
30
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/name.js
vendored
Normal file
30
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/name.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2022 Mathias Bynens, Ron Buckton, and the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-get-regexp.prototype.unicodeSets
|
||||
description: >
|
||||
RegExp.prototype.unicodeSets name
|
||||
info: |
|
||||
17 ECMAScript Standard Built-in Objects
|
||||
|
||||
Functions that are specified as get or set accessor functions of built-in
|
||||
properties have "get " or "set " prepended to the property name string.
|
||||
includes: [propertyHelper.js]
|
||||
features: [regexp-v-flag]
|
||||
---*/
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(RegExp.prototype, "unicodeSets");
|
||||
|
||||
assert.sameValue(
|
||||
desc.get.name,
|
||||
"get unicodeSets"
|
||||
);
|
||||
|
||||
verifyProperty(desc.get, "name", {
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
reportCompare(0, 0);
|
32
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/prop-desc.js
vendored
Normal file
32
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/prop-desc.js
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2022 Mathias Bynens, Ron Buckton, and the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
esid: sec-get-regexp.prototype.unicodeSets
|
||||
description: >
|
||||
`pending` property descriptor
|
||||
info: |
|
||||
RegExp.prototype.unicodeSets is an accessor property whose set accessor
|
||||
function is undefined.
|
||||
|
||||
17 ECMAScript Standard Built-in Objects
|
||||
|
||||
Every accessor property described in clauses 18 through 26 and in Annex B.2 has the attributes
|
||||
{ [[Enumerable]]: false, [[Configurable]]: true } unless otherwise specified. If only a get
|
||||
accessor function is described, the set accessor function is the default value, undefined. If
|
||||
only a set accessor is described the get accessor is the default value, undefined.
|
||||
includes: [propertyHelper.js]
|
||||
features: [regexp-v-flag]
|
||||
---*/
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(RegExp.prototype, "unicodeSets");
|
||||
|
||||
assert.sameValue(desc.set, undefined);
|
||||
assert.sameValue(typeof desc.get, "function");
|
||||
|
||||
verifyProperty(RegExp.prototype, "unicodeSets", {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
reportCompare(0, 0);
|
0
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/shell.js
vendored
Normal file
0
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/shell.js
vendored
Normal file
37
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/this-val-invalid-obj.js
vendored
Normal file
37
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/this-val-invalid-obj.js
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2022 Mathias Bynens, Ron Buckton, and the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-get-regexp.prototype.unicodeSets
|
||||
description: Invoked on an object without an [[OriginalFlags]] internal slot
|
||||
info: |
|
||||
get RegExp.prototype.unicodeSets -> RegExpHasFlag
|
||||
|
||||
1. Let R be the this value.
|
||||
2. If Type(R) is not Object, throw a TypeError exception.
|
||||
3. If R does not have an [[OriginalFlags]] internal slot, then
|
||||
a. If SameValue(R, %RegExpPrototype%) is true, return undefined.
|
||||
b. Otherwise, throw a TypeError exception.
|
||||
features: [regexp-v-flag]
|
||||
---*/
|
||||
|
||||
var unicodeSets = Object.getOwnPropertyDescriptor(RegExp.prototype, 'unicodeSets').get;
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call({});
|
||||
}, 'ordinary object');
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call([]);
|
||||
}, 'array exotic object');
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(arguments);
|
||||
}, 'arguments object');
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(() => {});
|
||||
}, 'function object');
|
||||
|
||||
reportCompare(0, 0);
|
47
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/this-val-non-obj.js
vendored
Normal file
47
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/this-val-non-obj.js
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2022 Mathias Bynens, Ron Buckton, and the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-get-regexp.prototype.unicodeSets
|
||||
description: >
|
||||
`unicodeSets` accessor invoked on a non-object value
|
||||
info: |
|
||||
get RegExp.prototype.unicodeSets -> RegExpHasFlag
|
||||
|
||||
1. Let R be the this value.
|
||||
2. If Type(R) is not Object, throw a TypeError exception.
|
||||
features: [Symbol, regexp-v-flag]
|
||||
---*/
|
||||
|
||||
var unicodeSets = Object.getOwnPropertyDescriptor(RegExp.prototype, "unicodeSets").get;
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(undefined);
|
||||
}, "undefined");
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(null);
|
||||
}, "null");
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(true);
|
||||
}, "true");
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call("string");
|
||||
}, "string");
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(Symbol("s"));
|
||||
}, "symbol");
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(4);
|
||||
}, "number");
|
||||
|
||||
assert.throws(TypeError, function() {
|
||||
unicodeSets.call(4n);
|
||||
}, "bigint");
|
||||
|
||||
reportCompare(0, 0);
|
24
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/this-val-regexp-prototype.js
vendored
Normal file
24
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/this-val-regexp-prototype.js
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2022 Mathias Bynens, Ron Buckton, and the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-get-regexp.prototype.unicodeSets
|
||||
description: >
|
||||
Return value of `undefined` when the "this" value is the RegExp prototype
|
||||
object
|
||||
info: |
|
||||
get RegExp.prototype.unicodeSets -> RegExpHasFlag
|
||||
|
||||
1. Let R be the this value.
|
||||
2. If Type(R) is not Object, throw a TypeError exception.
|
||||
3. If R does not have an [[OriginalFlags]] internal slot, then
|
||||
a. If SameValue(R, %RegExpPrototype%) is true, return undefined.
|
||||
features: [regexp-v-flag]
|
||||
---*/
|
||||
|
||||
var get = Object.getOwnPropertyDescriptor(RegExp.prototype, "unicodeSets").get;
|
||||
|
||||
assert.sameValue(get.call(RegExp.prototype), undefined);
|
||||
|
||||
reportCompare(0, 0);
|
54
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/this-val-regexp.js
vendored
Normal file
54
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/this-val-regexp.js
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright (C) 2022 Mathias Bynens, Ron Buckton, and the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-get-regexp.prototype.unicodeSets
|
||||
description: >
|
||||
`unicodeSets` accessor function invoked on a RegExp instance
|
||||
info: |
|
||||
get RegExp.prototype.unicodeSets -> RegExpHasFlag
|
||||
|
||||
4. Let flags be the value of R’s [[OriginalFlags]] internal slot.
|
||||
5. If flags contains the code unit "s", return true.
|
||||
6. Return false.
|
||||
features: [regexp-v-flag]
|
||||
---*/
|
||||
|
||||
assert.sameValue(/./.unicodeSets, false, "/./.unicodeSets");
|
||||
assert.sameValue(/./d.unicodeSets, false, "/./d.unicodeSets");
|
||||
assert.sameValue(/./g.unicodeSets, false, "/./g.unicodeSets");
|
||||
assert.sameValue(/./i.unicodeSets, false, "/./i.unicodeSets");
|
||||
assert.sameValue(/./m.unicodeSets, false, "/./m.unicodeSets");
|
||||
assert.sameValue(/./s.unicodeSets, false, "/./s.unicodeSets");
|
||||
assert.sameValue(/./u.unicodeSets, false, "/./u.unicodeSets");
|
||||
assert.sameValue(/./y.unicodeSets, false, "/./y.unicodeSets");
|
||||
|
||||
assert.sameValue(/./v.unicodeSets, true, "/./v.unicodeSets");
|
||||
assert.sameValue(/./vd.unicodeSets, true, "/./vd.unicodeSets");
|
||||
assert.sameValue(/./vg.unicodeSets, true, "/./vg.unicodeSets");
|
||||
assert.sameValue(/./vi.unicodeSets, true, "/./vi.unicodeSets");
|
||||
assert.sameValue(/./vm.unicodeSets, true, "/./vm.unicodeSets");
|
||||
assert.sameValue(/./vs.unicodeSets, true, "/./vs.unicodeSets");
|
||||
// Note: `/vu` throws an early parse error and is tested separately.
|
||||
assert.sameValue(/./vy.unicodeSets, true, "/./vy.unicodeSets");
|
||||
|
||||
assert.sameValue(new RegExp(".", "").unicodeSets, false, "new RegExp('.', '').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "d").unicodeSets, false, "new RegExp('.', 'd').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "g").unicodeSets, false, "new RegExp('.', 'g').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "i").unicodeSets, false, "new RegExp('.', 'i').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "m").unicodeSets, false, "new RegExp('.', 'm').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "s").unicodeSets, false, "new RegExp('.', 's').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "u").unicodeSets, false, "new RegExp('.', 'u').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "y").unicodeSets, false, "new RegExp('.', 'y').unicodeSets");
|
||||
|
||||
assert.sameValue(new RegExp(".", "v").unicodeSets, true, "new RegExp('.', 'v').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "vd").unicodeSets, true, "new RegExp('.', 'vd').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "vg").unicodeSets, true, "new RegExp('.', 'vg').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "vi").unicodeSets, true, "new RegExp('.', 'vi').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "vm").unicodeSets, true, "new RegExp('.', 'vm').unicodeSets");
|
||||
assert.sameValue(new RegExp(".", "vs").unicodeSets, true, "new RegExp('.', 'vs').unicodeSets");
|
||||
// Note: `new RegExp(pattern, 'vu')` throws a runtime error and is tested separately.
|
||||
assert.sameValue(new RegExp(".", "vy").unicodeSets, true, "new RegExp('.', 'vy').unicodeSets");
|
||||
|
||||
reportCompare(0, 0);
|
17
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/uv-flags-constructor.js
vendored
Normal file
17
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/uv-flags-constructor.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// |reftest| skip -- regexp-v-flag is not supported
|
||||
// Copyright 2022 Mathias Bynens. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
author: Mathias Bynens
|
||||
description: >
|
||||
Setting the `u` and `v` flag at the same time produces an error.
|
||||
esid: sec-parsepattern
|
||||
features: [regexp-v-flag]
|
||||
---*/
|
||||
|
||||
assert.throws(SyntaxError, function() {
|
||||
new RegExp(".", "uv");
|
||||
});
|
||||
|
||||
reportCompare(0, 0);
|
18
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/uv-flags.js
vendored
Normal file
18
js/src/tests/test262/built-ins/RegExp/prototype/unicodeSets/uv-flags.js
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// |reftest| skip error:SyntaxError -- regexp-v-flag is not supported
|
||||
// Copyright 2022 Mathias Bynens. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
author: Mathias Bynens
|
||||
description: >
|
||||
Setting the `u` and `v` flag at the same time produces an error.
|
||||
esid: sec-parsepattern
|
||||
negative:
|
||||
phase: parse
|
||||
type: SyntaxError
|
||||
features: [regexp-v-flag]
|
||||
---*/
|
||||
|
||||
$DONOTEVALUATE();
|
||||
|
||||
/./uv;
|
@ -1,3 +1,4 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty('SharedArrayBuffer')) -- SharedArrayBuffer is not enabled unconditionally
|
||||
// Copyright (C) 2021 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
@ -7,6 +8,7 @@ info: |
|
||||
This property has the attributes { [[Writable]]: false, [[Enumerable]]:
|
||||
false, [[Configurable]]: false }.
|
||||
includes: [propertyHelper.js]
|
||||
features: [SharedArrayBuffer]
|
||||
---*/
|
||||
|
||||
verifyProperty(SharedArrayBuffer, 'prototype', {
|
||||
|
31
js/src/tests/test262/built-ins/Temporal/Duration/prototype/add/argument-invalid-property.js
vendored
Normal file
31
js/src/tests/test262/built-ins/Temporal/Duration/prototype/add/argument-invalid-property.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.add
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
20
js/src/tests/test262/built-ins/Temporal/Duration/prototype/add/argument-mixed-sign.js
vendored
Normal file
20
js/src/tests/test262/built-ins/Temporal/Duration/prototype/add/argument-mixed-sign.js
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.add
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.add({ hours: 1, minutes: -30 }),
|
||||
`mixed positive and negative values always throw`
|
||||
);
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
22
js/src/tests/test262/built-ins/Temporal/Duration/prototype/add/argument-not-object.js
vendored
Normal file
22
js/src/tests/test262/built-ins/Temporal/Duration/prototype/add/argument-not-object.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.add
|
||||
description: Passing a primitive other than string to add() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
assert.throws(RangeError, () => instance.add(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.add(null), "null");
|
||||
assert.throws(RangeError, () => instance.add(true), "boolean");
|
||||
assert.throws(RangeError, () => instance.add(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.add(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.add(7), "number");
|
||||
assert.throws(RangeError, () => instance.add(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.add([]), "array");
|
||||
assert.throws(TypeError, () => instance.add(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,16 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.add
|
||||
description: Mixed positive and negative values or missing properties always throw
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const duration = Temporal.Duration.from({ days: 1, minutes: 5 });
|
||||
assert.throws(RangeError, () => duration.add({ hours: 1, minutes: -30 }), "mixed signs");
|
||||
assert.throws(TypeError, () => duration.add({}), "no properties");
|
||||
assert.throws(TypeError, () => duration.add({ month: 12 }), "only singular 'month' property");
|
||||
|
||||
reportCompare(0, 0);
|
30
js/src/tests/test262/built-ins/Temporal/Duration/prototype/add/argument-singular-properties.js
vendored
Normal file
30
js/src/tests/test262/built-ins/Temporal/Duration/prototype/add/argument-singular-properties.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.add
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.add(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,7 +8,7 @@ description: A non-integer value for any recognized property in the property bag
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 654, 321);
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
const fields = [
|
||||
"years",
|
||||
"months",
|
||||
|
31
js/src/tests/test262/built-ins/Temporal/Duration/prototype/subtract/argument-invalid-property.js
vendored
Normal file
31
js/src/tests/test262/built-ins/Temporal/Duration/prototype/subtract/argument-invalid-property.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.subtract
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
19
js/src/tests/test262/built-ins/Temporal/Duration/prototype/subtract/argument-mixed-sign.js
vendored
Normal file
19
js/src/tests/test262/built-ins/Temporal/Duration/prototype/subtract/argument-mixed-sign.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.subtract
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.subtract({ hours: 1, minutes: -30 }),
|
||||
`mixed positive and negative values always throw`
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
22
js/src/tests/test262/built-ins/Temporal/Duration/prototype/subtract/argument-not-object.js
vendored
Normal file
22
js/src/tests/test262/built-ins/Temporal/Duration/prototype/subtract/argument-not-object.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.subtract
|
||||
description: Passing a primitive other than string to subtract() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
assert.throws(RangeError, () => instance.subtract(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.subtract(null), "null");
|
||||
assert.throws(RangeError, () => instance.subtract(true), "boolean");
|
||||
assert.throws(RangeError, () => instance.subtract(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.subtract(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.subtract(7), "number");
|
||||
assert.throws(RangeError, () => instance.subtract(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.subtract([]), "array");
|
||||
assert.throws(TypeError, () => instance.subtract(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,16 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.subtract
|
||||
description: Mixed positive and negative values or missing properties always throw
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const duration = Temporal.Duration.from({ days: 1, minutes: 5 });
|
||||
assert.throws(RangeError, () => duration.subtract({ hours: 1, minutes: -30 }), "mixed signs");
|
||||
assert.throws(TypeError, () => duration.subtract({}), "no properties");
|
||||
assert.throws(TypeError, () => duration.subtract({ month: 12 }), "only singular 'month' property");
|
||||
|
||||
reportCompare(0, 0);
|
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.subtract
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.subtract(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,7 +8,7 @@ description: A non-integer value for any recognized property in the property bag
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 654, 321);
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
const fields = [
|
||||
"years",
|
||||
"months",
|
||||
|
@ -1,16 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.with
|
||||
description: Singular properties are ignored.
|
||||
includes: [temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const d = Temporal.Duration.from({ years: 5, days: 1 });
|
||||
const d2 = d.with({ year: 1, days: 0 });
|
||||
TemporalHelpers.assertDuration(d2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
reportCompare(0, 0);
|
31
js/src/tests/test262/built-ins/Temporal/Duration/prototype/with/argument-invalid-property.js
vendored
Normal file
31
js/src/tests/test262/built-ins/Temporal/Duration/prototype/with/argument-invalid-property.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.with
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.with({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.with({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.with({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -4,11 +4,16 @@
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.with
|
||||
description: The durationLike argument must not contain different signs.
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const d = new Temporal.Duration(1, 2, 3, 4, 5);
|
||||
assert.throws(RangeError, () => d.with({ hours: 1, minutes: -1 }));
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.with({ hours: 1, minutes: -30 }),
|
||||
`mixed positive and negative values always throw`
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
23
js/src/tests/test262/built-ins/Temporal/Duration/prototype/with/argument-not-object.js
vendored
Normal file
23
js/src/tests/test262/built-ins/Temporal/Duration/prototype/with/argument-not-object.js
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.with
|
||||
description: Passing a primitive other than string to with() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
assert.throws(TypeError, () => instance.with(undefined), "undefined");
|
||||
assert.throws(TypeError, () => instance.with(null), "null");
|
||||
assert.throws(TypeError, () => instance.with(true), "boolean");
|
||||
assert.throws(TypeError, () => instance.with(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.with(Symbol()), "Symbol");
|
||||
assert.throws(TypeError, () => instance.with(7), "number");
|
||||
assert.throws(TypeError, () => instance.with(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.with([]), "array");
|
||||
assert.throws(TypeError, () => instance.with(() => {}), "function");
|
||||
assert.throws(TypeError, () => instance.with("string"), "string");
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,17 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.with
|
||||
description: Passing a sign property is not supported.
|
||||
includes: [temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const d = Temporal.Duration.from({ years: 5, days: 1 });
|
||||
assert.throws(TypeError, () => d.with({ sign: -1 }));
|
||||
const d2 = d.with({ sign: -1, days: 0 });
|
||||
TemporalHelpers.assertDuration(d2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,21 +1,17 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2021 the V8 project authors. All rights reserved.
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.with
|
||||
description: >
|
||||
The durationLike argument must contain at least one correctly spelled property
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
let d = new Temporal.Duration(1, 2, 3, 4, 5);
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
|
||||
[
|
||||
{},
|
||||
[],
|
||||
() => {},
|
||||
// objects with only singular keys (plural is the correct spelling)
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
@ -27,8 +23,9 @@ let d = new Temporal.Duration(1, 2, 3, 4, 5);
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => d.with(badObject),
|
||||
assert.throws(TypeError, () => instance.with(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,30 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2021 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.duration.prototype.with
|
||||
description: Throw TypeError if the temporalDurationLike argument is the wrong type
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
let d = new Temporal.Duration(1, 2, 3, 4, 5);
|
||||
|
||||
[
|
||||
"string",
|
||||
"P1YT1M",
|
||||
true,
|
||||
false,
|
||||
NaN,
|
||||
Infinity,
|
||||
undefined,
|
||||
null,
|
||||
123,
|
||||
Symbol(),
|
||||
456n,
|
||||
].forEach((badInput) => {
|
||||
assert.throws(TypeError, () => d.with(badInput),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,7 +8,7 @@ description: A non-integer value for any recognized property in the property bag
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 987, 654, 321);
|
||||
const instance = new Temporal.Duration(0, 0, 0, 1, 2, 3, 4, 987, 654, 321);
|
||||
const fields = [
|
||||
"years",
|
||||
"months",
|
||||
|
31
js/src/tests/test262/built-ins/Temporal/Instant/prototype/add/argument-invalid-property.js
vendored
Normal file
31
js/src/tests/test262/built-ins/Temporal/Instant/prototype/add/argument-invalid-property.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.instant.prototype.add
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Instant(1_000_000_000_000_000_000n);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
19
js/src/tests/test262/built-ins/Temporal/Instant/prototype/add/argument-mixed-sign.js
vendored
Normal file
19
js/src/tests/test262/built-ins/Temporal/Instant/prototype/add/argument-mixed-sign.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.instant.prototype.add
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Instant(1_000_000_000_000_000_000n);
|
||||
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.add({ hours: 1, minutes: -30 }),
|
||||
`mixed positive and negative values always throw`
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
22
js/src/tests/test262/built-ins/Temporal/Instant/prototype/add/argument-not-object.js
vendored
Normal file
22
js/src/tests/test262/built-ins/Temporal/Instant/prototype/add/argument-not-object.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.instant.prototype.add
|
||||
description: Passing a primitive other than string to add() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Instant(1_000_000_000_000_000_000n);
|
||||
assert.throws(RangeError, () => instance.add(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.add(null), "null");
|
||||
assert.throws(RangeError, () => instance.add(true), "boolean");
|
||||
assert.throws(RangeError, () => instance.add(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.add(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.add(7), "number");
|
||||
assert.throws(RangeError, () => instance.add(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.add([]), "array");
|
||||
assert.throws(TypeError, () => instance.add(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
30
js/src/tests/test262/built-ins/Temporal/Instant/prototype/add/argument-singular-properties.js
vendored
Normal file
30
js/src/tests/test262/built-ins/Temporal/Instant/prototype/add/argument-singular-properties.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.instant.prototype.add
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Instant(1_000_000_000_000_000_000n);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.add(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
31
js/src/tests/test262/built-ins/Temporal/Instant/prototype/subtract/argument-invalid-property.js
vendored
Normal file
31
js/src/tests/test262/built-ins/Temporal/Instant/prototype/subtract/argument-invalid-property.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.instant.prototype.subtract
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Instant(1_000_000_000_000_000_000n);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
19
js/src/tests/test262/built-ins/Temporal/Instant/prototype/subtract/argument-mixed-sign.js
vendored
Normal file
19
js/src/tests/test262/built-ins/Temporal/Instant/prototype/subtract/argument-mixed-sign.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.instant.prototype.subtract
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Instant(1_000_000_000_000_000_000n);
|
||||
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.subtract({ hours: 1, minutes: -30 }),
|
||||
`mixed positive and negative values always throw`
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
22
js/src/tests/test262/built-ins/Temporal/Instant/prototype/subtract/argument-not-object.js
vendored
Normal file
22
js/src/tests/test262/built-ins/Temporal/Instant/prototype/subtract/argument-not-object.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.instant.prototype.subtract
|
||||
description: Passing a primitive other than string to subtract() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Instant(1_000_000_000_000_000_000n);
|
||||
assert.throws(RangeError, () => instance.subtract(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.subtract(null), "null");
|
||||
assert.throws(RangeError, () => instance.subtract(true), "boolean");
|
||||
assert.throws(RangeError, () => instance.subtract(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.subtract(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.subtract(7), "number");
|
||||
assert.throws(RangeError, () => instance.subtract(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.subtract([]), "array");
|
||||
assert.throws(TypeError, () => instance.subtract(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.instant.prototype.subtract
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.Instant(1_000_000_000_000_000_000n);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.subtract(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,19 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.add
|
||||
description: RangeError thrown when signs don't match in the duration
|
||||
includes: [temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const calendar = TemporalHelpers.calendarThrowEverything();
|
||||
const date = new Temporal.PlainDate(2000, 5, 2, calendar);
|
||||
const duration = { months: 1, days: -30 };
|
||||
for (const overflow of ["constrain", "reject"]) {
|
||||
assert.throws(RangeError, () => date.add(duration, { overflow }));
|
||||
}
|
||||
|
||||
reportCompare(0, 0);
|
31
js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-invalid-property.js
vendored
Normal file
31
js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-invalid-property.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.add
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDate(2000, 5, 2);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,21 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.add
|
||||
description: TypeError for missing properties
|
||||
includes: [temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const date = new Temporal.PlainDate(2000, 5, 2);
|
||||
const options = {
|
||||
get overflow() {
|
||||
TemporalHelpers.assertUnreachable("should not get overflow");
|
||||
}
|
||||
};
|
||||
assert.throws(TypeError, () => date.add({}, options), "empty object");
|
||||
assert.throws(TypeError, () => date.add({ month: 12 }, options), "misspelled 'months'");
|
||||
|
||||
reportCompare(0, 0);
|
21
js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-mixed-sign.js
vendored
Normal file
21
js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-mixed-sign.js
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.add
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDate(2000, 5, 2);
|
||||
|
||||
["constrain", "reject"].forEach((overflow) => {
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.add({ hours: 1, minutes: -30 }, { overflow }),
|
||||
`mixed positive and negative values always throw (overflow = "${overflow}")`
|
||||
);
|
||||
});
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,7 +8,7 @@ description: Passing a primitive other than string to add() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 });
|
||||
const instance = new Temporal.PlainDate(2000, 5, 2);
|
||||
assert.throws(RangeError, () => instance.add(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.add(null), "null");
|
||||
assert.throws(RangeError, () => instance.add(true), "boolean");
|
||||
@ -16,5 +16,7 @@ assert.throws(RangeError, () => instance.add(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.add(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.add(7), "number");
|
||||
assert.throws(RangeError, () => instance.add(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.add([]), "array");
|
||||
assert.throws(TypeError, () => instance.add(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
30
js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-singular-properties.js
vendored
Normal file
30
js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/add/argument-singular-properties.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.add
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDate(2000, 5, 2);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.add(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,16 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.add
|
||||
description: Ignores singular properties
|
||||
includes: [temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const date = Temporal.PlainDate.from("2019-11-18");
|
||||
TemporalHelpers.assertPlainDate(date.add({ month: 1, days: 1 }),
|
||||
2019, 11, "M11", 19);
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,19 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.subtract
|
||||
description: RangeError thrown when signs don't match in the duration
|
||||
includes: [temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const calendar = TemporalHelpers.calendarThrowEverything();
|
||||
const date = new Temporal.PlainDate(2000, 5, 2, calendar);
|
||||
const duration = { months: 1, days: -30 };
|
||||
for (const overflow of ["constrain", "reject"]) {
|
||||
assert.throws(RangeError, () => date.subtract(duration, { overflow }));
|
||||
}
|
||||
|
||||
reportCompare(0, 0);
|
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.subtract
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDate(2000, 5, 2);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,21 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.subtract
|
||||
description: TypeError for missing properties
|
||||
includes: [temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const date = new Temporal.PlainDate(2000, 5, 2);
|
||||
const options = {
|
||||
get overflow() {
|
||||
TemporalHelpers.assertUnreachable("should not get overflow");
|
||||
}
|
||||
};
|
||||
assert.throws(TypeError, () => date.subtract({}, options), "empty object");
|
||||
assert.throws(TypeError, () => date.subtract({ month: 12 }, options), "misspelled 'months'");
|
||||
|
||||
reportCompare(0, 0);
|
21
js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-mixed-sign.js
vendored
Normal file
21
js/src/tests/test262/built-ins/Temporal/PlainDate/prototype/subtract/argument-mixed-sign.js
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.subtract
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDate(2000, 5, 2);
|
||||
|
||||
["constrain", "reject"].forEach((overflow) => {
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.subtract({ hours: 1, minutes: -30 }, { overflow }),
|
||||
`mixed positive and negative values always throw (overflow = "${overflow}")`
|
||||
);
|
||||
});
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,7 +8,7 @@ description: Passing a primitive other than string to subtract() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = Temporal.PlainDate.from({ year: 2000, month: 5, day: 2 });
|
||||
const instance = new Temporal.PlainDate(2000, 5, 2);
|
||||
assert.throws(RangeError, () => instance.subtract(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.subtract(null), "null");
|
||||
assert.throws(RangeError, () => instance.subtract(true), "boolean");
|
||||
@ -16,5 +16,7 @@ assert.throws(RangeError, () => instance.subtract(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.subtract(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.subtract(7), "number");
|
||||
assert.throws(RangeError, () => instance.subtract(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.subtract([]), "array");
|
||||
assert.throws(TypeError, () => instance.subtract(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.subtract
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDate(2000, 5, 2);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.subtract(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -1,16 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindate.prototype.subtract
|
||||
description: Ignores singular properties
|
||||
includes: [temporalHelpers.js]
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const date = Temporal.PlainDate.from("2019-11-18");
|
||||
TemporalHelpers.assertPlainDate(date.subtract({ month: 1, days: 1 }),
|
||||
2019, 11, "M11", 17);
|
||||
|
||||
reportCompare(0, 0);
|
31
js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-invalid-property.js
vendored
Normal file
31
js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/add/argument-invalid-property.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindatetime.prototype.add
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,12 +8,12 @@ description: Positive and negative values in the temporalDurationLike argument a
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0);
|
||||
const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
|
||||
|
||||
["constrain", "reject"].forEach((overflow) => {
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => jan31.add({ hours: 1, minutes: -30 }, { overflow }),
|
||||
() => instance.add({ hours: 1, minutes: -30 }, { overflow }),
|
||||
`mixed positive and negative values always throw (overflow = "${overflow}")`
|
||||
);
|
||||
});
|
@ -8,7 +8,7 @@ description: Passing a primitive other than string to add() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 });
|
||||
const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
|
||||
assert.throws(RangeError, () => instance.add(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.add(null), "null");
|
||||
assert.throws(RangeError, () => instance.add(true), "boolean");
|
||||
@ -16,5 +16,7 @@ assert.throws(RangeError, () => instance.add(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.add(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.add(7), "number");
|
||||
assert.throws(RangeError, () => instance.add(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.add([]), "array");
|
||||
assert.throws(TypeError, () => instance.add(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
@ -1,38 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindatetime.prototype.add
|
||||
description: At least one recognized property has to be present in argument
|
||||
features: [Temporal]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => jan31.add({}),
|
||||
"empty object not acceptable"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => jan31.add({ month: 12 }), // should be "months"
|
||||
"misspelled property in argument throws if no other properties are present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => jan31.add({ nonsense: true }),
|
||||
"unrecognized properties throw if no other recognized property is present"
|
||||
);
|
||||
|
||||
TemporalHelpers.assertPlainDateTime(
|
||||
jan31.add({ nonsense: 1, days: 1 }),
|
||||
2020, 2, "M02", 1, 15, 0, 0, 0, 0, 0,
|
||||
"unrecognized properties ignored provided at least one recognized property is present"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindatetime.prototype.add
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.add(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindatetime.prototype.subtract
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,12 +8,12 @@ description: Positive and negative values in the temporalDurationLike argument a
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0);
|
||||
const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
|
||||
|
||||
["constrain", "reject"].forEach((overflow) => {
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => jan31.subtract({ hours: 1, minutes: -30 }, { overflow }),
|
||||
() => instance.subtract({ hours: 1, minutes: -30 }, { overflow }),
|
||||
`mixed positive and negative values always throw (overflow = "${overflow}")`
|
||||
);
|
||||
});
|
@ -8,7 +8,7 @@ description: Passing a primitive other than string to subtract() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 });
|
||||
const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
|
||||
assert.throws(RangeError, () => instance.subtract(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.subtract(null), "null");
|
||||
assert.throws(RangeError, () => instance.subtract(true), "boolean");
|
||||
@ -16,5 +16,7 @@ assert.throws(RangeError, () => instance.subtract(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.subtract(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.subtract(7), "number");
|
||||
assert.throws(RangeError, () => instance.subtract(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.subtract([]), "array");
|
||||
assert.throws(TypeError, () => instance.subtract(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
@ -1,38 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindatetime.prototype.subtract
|
||||
description: At least one recognized property has to be present in argument
|
||||
features: [Temporal]
|
||||
includes: [temporalHelpers.js]
|
||||
---*/
|
||||
|
||||
const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => jan31.subtract({}),
|
||||
"empty object not acceptable"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => jan31.subtract({ month: 12 }), // should be "months"
|
||||
"misspelled property in argument throws if no other properties are present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => jan31.subtract({ nonsense: true }),
|
||||
"unrecognized properties throw if no other recognized property is present"
|
||||
);
|
||||
|
||||
TemporalHelpers.assertPlainDateTime(
|
||||
jan31.subtract({ nonsense: 1, days: 1 }),
|
||||
2020, 1, "M01", 30, 15, 0, 0, 0, 0, 0,
|
||||
"unrecognized properties ignored provided at least one recognized property is present"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaindatetime.prototype.subtract
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.subtract(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -0,0 +1,16 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plainmonthday
|
||||
description: referenceISOYear argument, if given, can cause RangeError
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const calendar = new Temporal.Calendar("iso8601");
|
||||
|
||||
assert.throws(RangeError, () => new Temporal.PlainMonthDay(9, 14, calendar, 275760), "after the maximum ISO date");
|
||||
assert.throws(RangeError, () => new Temporal.PlainMonthDay(4, 18, calendar, -271821), "before the minimum ISO date")
|
||||
|
||||
reportCompare(0, 0);
|
31
js/src/tests/test262/built-ins/Temporal/PlainTime/prototype/add/argument-invalid-property.js
vendored
Normal file
31
js/src/tests/test262/built-ins/Temporal/PlainTime/prototype/add/argument-invalid-property.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaintime.prototype.add
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainTime(15, 30, 45, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.add({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
19
js/src/tests/test262/built-ins/Temporal/PlainTime/prototype/add/argument-mixed-sign.js
vendored
Normal file
19
js/src/tests/test262/built-ins/Temporal/PlainTime/prototype/add/argument-mixed-sign.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaintime.prototype.add
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainTime(15, 30, 45, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.add({ hours: 1, minutes: -30 }),
|
||||
`mixed positive and negative values always throw`
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,7 +8,7 @@ description: Passing a primitive other than string to add() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = Temporal.PlainTime.from({ hour: 12, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 });
|
||||
const instance = new Temporal.PlainTime(15, 30, 45, 987, 654, 321);
|
||||
assert.throws(RangeError, () => instance.add(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.add(null), "null");
|
||||
assert.throws(RangeError, () => instance.add(true), "boolean");
|
||||
@ -16,5 +16,7 @@ assert.throws(RangeError, () => instance.add(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.add(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.add(7), "number");
|
||||
assert.throws(RangeError, () => instance.add(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.add([]), "array");
|
||||
assert.throws(TypeError, () => instance.add(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
@ -1,16 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaintime.prototype.add
|
||||
description: Mixed positive and negative values or missing properties always throw
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const plainTime = new Temporal.PlainTime(12, 34, 56, 123, 987, 500);
|
||||
assert.throws(RangeError, () => plainTime.add({ hours: 1, minutes: -6 }), "mixed signs");
|
||||
assert.throws(TypeError, () => plainTime.add({}), "no properties");
|
||||
assert.throws(TypeError, () => plainTime.add({ hour: 12 }), "only singular 'hour' property");
|
||||
|
||||
reportCompare(0, 0);
|
30
js/src/tests/test262/built-ins/Temporal/PlainTime/prototype/add/argument-singular-properties.js
vendored
Normal file
30
js/src/tests/test262/built-ins/Temporal/PlainTime/prototype/add/argument-singular-properties.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaintime.prototype.add
|
||||
description: Singular properties in the property bag are always ignored
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainTime(15, 30, 45, 987, 654, 321);
|
||||
|
||||
[
|
||||
{ year: 1 },
|
||||
{ month: 2 },
|
||||
{ week: 3 },
|
||||
{ day: 4 },
|
||||
{ hour: 5 },
|
||||
{ minute: 6 },
|
||||
{ second: 7 },
|
||||
{ millisecond: 8 },
|
||||
{ microsecond: 9 },
|
||||
{ nanosecond: 10 },
|
||||
].forEach((badObject) => {
|
||||
assert.throws(TypeError, () => instance.add(badObject),
|
||||
"Throw TypeError if temporalDurationLike is not valid");
|
||||
});
|
||||
|
||||
|
||||
reportCompare(0, 0);
|
@ -0,0 +1,31 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaintime.prototype.subtract
|
||||
description: temporalDurationLike object must contain at least one correctly spelled property
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainTime(15, 30, 45, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({}),
|
||||
"Throws TypeError if no property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ nonsense: true }),
|
||||
"Throws TypeError if no recognized property is present"
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
TypeError,
|
||||
() => instance.subtract({ sign: 1 }),
|
||||
"Sign property is not recognized"
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
19
js/src/tests/test262/built-ins/Temporal/PlainTime/prototype/subtract/argument-mixed-sign.js
vendored
Normal file
19
js/src/tests/test262/built-ins/Temporal/PlainTime/prototype/subtract/argument-mixed-sign.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaintime.prototype.subtract
|
||||
description: Positive and negative values in the temporalDurationLike argument are not acceptable
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const instance = new Temporal.PlainTime(15, 30, 45, 987, 654, 321);
|
||||
|
||||
assert.throws(
|
||||
RangeError,
|
||||
() => instance.subtract({ hours: 1, minutes: -30 }),
|
||||
`mixed positive and negative values always throw`
|
||||
);
|
||||
|
||||
reportCompare(0, 0);
|
@ -8,7 +8,7 @@ description: Passing a primitive other than string to subtract() throws
|
||||
features: [Symbol, Temporal]
|
||||
---*/
|
||||
|
||||
const instance = Temporal.PlainTime.from({ hour: 12, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 });
|
||||
const instance = new Temporal.PlainTime(15, 30, 45, 987, 654, 321);
|
||||
assert.throws(RangeError, () => instance.subtract(undefined), "undefined");
|
||||
assert.throws(RangeError, () => instance.subtract(null), "null");
|
||||
assert.throws(RangeError, () => instance.subtract(true), "boolean");
|
||||
@ -16,5 +16,7 @@ assert.throws(RangeError, () => instance.subtract(""), "empty string");
|
||||
assert.throws(TypeError, () => instance.subtract(Symbol()), "Symbol");
|
||||
assert.throws(RangeError, () => instance.subtract(7), "number");
|
||||
assert.throws(RangeError, () => instance.subtract(7n), "bigint");
|
||||
assert.throws(TypeError, () => instance.subtract([]), "array");
|
||||
assert.throws(TypeError, () => instance.subtract(() => {}), "function");
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
@ -1,16 +0,0 @@
|
||||
// |reftest| skip -- Temporal is not supported
|
||||
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
esid: sec-temporal.plaintime.prototype.subtract
|
||||
description: Mixed positive and negative values or missing properties always throw
|
||||
features: [Temporal]
|
||||
---*/
|
||||
|
||||
const plainTime = new Temporal.PlainTime(12, 34, 56, 123, 987, 500);
|
||||
assert.throws(RangeError, () => plainTime.subtract({ hours: 1, minutes: -6 }), "mixed signs");
|
||||
assert.throws(TypeError, () => plainTime.subtract({}), "no properties");
|
||||
assert.throws(TypeError, () => plainTime.subtract({ hour: 12 }), "only singular 'hour' property");
|
||||
|
||||
reportCompare(0, 0);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user