mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 20:29:11 +00:00
chore: use primordials in 40_testing.js (#21422)
This commit brings back usage of primordials in "40_testing.js" by turning it back into an ES module and using new "lazy loading" functionality of ES modules coming from "deno_core". The same approach was applied to "40_jupyter.js". Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
parent
2235a1a359
commit
c5c5dea90d
9 changed files with 1561 additions and 1566 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -1065,9 +1065,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_core"
|
name = "deno_core"
|
||||||
version = "0.236.0"
|
version = "0.237.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ea0ab6f78d50bc3c9730f3a7faa3b9b32463b25f4af3dd0f02c6a18d995047e"
|
checksum = "a2ea708c221abdb5734e3c4b72075379c3046eb0ac54afa0ecb5e58509cce72c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -1493,9 +1493,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_ops"
|
name = "deno_ops"
|
||||||
version = "0.112.0"
|
version = "0.113.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8050c4964e689fb05cac12df6c52727950b44ce48bdd6b5e4d3c0332f2e7aa76"
|
checksum = "e5b9c0f6360795fb625774a8b5955c87c470c43159670cf5d2052df5ce9d84bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-rules",
|
"proc-macro-rules",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -4638,9 +4638,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_v8"
|
name = "serde_v8"
|
||||||
version = "0.145.0"
|
version = "0.146.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbd782806b3088c7083a142be36ceb734ccfb1da6f82b5eb84a2bff2b4a68efe"
|
checksum = "78309bd1ec4d14d165f271e203bdc45ad5bf45525da57bb70901f57942f6c0f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
|
|
@ -40,7 +40,7 @@ repository = "https://github.com/denoland/deno"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
deno_ast = { version = "0.31.6", features = ["transpiling"] }
|
deno_ast = { version = "0.31.6", features = ["transpiling"] }
|
||||||
deno_core = { version = "0.236.0" }
|
deno_core = { version = "0.237.0" }
|
||||||
|
|
||||||
deno_runtime = { version = "0.135.0", path = "./runtime" }
|
deno_runtime = { version = "0.135.0", path = "./runtime" }
|
||||||
napi_sym = { version = "0.57.0", path = "./cli/napi/sym" }
|
napi_sym = { version = "0.57.0", path = "./cli/napi/sym" }
|
||||||
|
|
|
@ -36,38 +36,36 @@
|
||||||
* }, { raw: true });
|
* }, { raw: true });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
(() => {
|
import { core, internals } from "ext:core/mod.js";
|
||||||
const internals = Deno[Deno.internal];
|
|
||||||
const core = internals.core;
|
|
||||||
|
|
||||||
const $display = Symbol.for("Jupyter.display");
|
const $display = Symbol.for("Jupyter.display");
|
||||||
|
|
||||||
/** Escape copied from https://deno.land/std@0.192.0/html/entities.ts */
|
/** Escape copied from https://deno.land/std@0.192.0/html/entities.ts */
|
||||||
const rawToEntityEntries = [
|
const rawToEntityEntries = [
|
||||||
["&", "&"],
|
["&", "&"],
|
||||||
["<", "<"],
|
["<", "<"],
|
||||||
[">", ">"],
|
[">", ">"],
|
||||||
['"', """],
|
['"', """],
|
||||||
["'", "'"],
|
["'", "'"],
|
||||||
];
|
];
|
||||||
|
|
||||||
const rawToEntity = new Map(rawToEntityEntries);
|
const rawToEntity = new Map(rawToEntityEntries);
|
||||||
|
|
||||||
const rawRe = new RegExp(`[${[...rawToEntity.keys()].join("")}]`, "g");
|
const rawRe = new RegExp(`[${[...rawToEntity.keys()].join("")}]`, "g");
|
||||||
|
|
||||||
function escapeHTML(str) {
|
function escapeHTML(str) {
|
||||||
return str.replaceAll(
|
return str.replaceAll(
|
||||||
rawRe,
|
rawRe,
|
||||||
(m) => rawToEntity.has(m) ? rawToEntity.get(m) : m,
|
(m) => rawToEntity.has(m) ? rawToEntity.get(m) : m,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Duck typing our way to common visualization and tabular libraries */
|
/** Duck typing our way to common visualization and tabular libraries */
|
||||||
/** Vegalite */
|
/** Vegalite */
|
||||||
function isVegaLike(obj) {
|
function isVegaLike(obj) {
|
||||||
return obj !== null && typeof obj === "object" && "toSpec" in obj;
|
return obj !== null && typeof obj === "object" && "toSpec" in obj;
|
||||||
}
|
}
|
||||||
function extractVega(obj) {
|
function extractVega(obj) {
|
||||||
const spec = obj.toSpec();
|
const spec = obj.toSpec();
|
||||||
if (!("$schema" in spec)) {
|
if (!("$schema" in spec)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -86,9 +84,9 @@
|
||||||
return {
|
return {
|
||||||
[mediaType]: spec,
|
[mediaType]: spec,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/** Polars */
|
/** Polars */
|
||||||
function isDataFrameLike(obj) {
|
function isDataFrameLike(obj) {
|
||||||
const isObject = obj !== null && typeof obj === "object";
|
const isObject = obj !== null && typeof obj === "object";
|
||||||
if (!isObject) {
|
if (!isObject) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -97,13 +95,13 @@
|
||||||
return df.schema !== void 0 && typeof df.schema === "object" &&
|
return df.schema !== void 0 && typeof df.schema === "object" &&
|
||||||
df.head !== void 0 && typeof df.head === "function" &&
|
df.head !== void 0 && typeof df.head === "function" &&
|
||||||
df.toRecords !== void 0 && typeof df.toRecords === "function";
|
df.toRecords !== void 0 && typeof df.toRecords === "function";
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Map Polars DataType to JSON Schema data types.
|
* Map Polars DataType to JSON Schema data types.
|
||||||
* @param dataType - The Polars DataType.
|
* @param dataType - The Polars DataType.
|
||||||
* @returns The corresponding JSON Schema data type.
|
* @returns The corresponding JSON Schema data type.
|
||||||
*/
|
*/
|
||||||
function mapPolarsTypeToJSONSchema(colType) {
|
function mapPolarsTypeToJSONSchema(colType) {
|
||||||
const typeMapping = {
|
const typeMapping = {
|
||||||
Null: "null",
|
Null: "null",
|
||||||
Bool: "boolean",
|
Bool: "boolean",
|
||||||
|
@ -129,9 +127,9 @@
|
||||||
// convert it to JSON
|
// convert it to JSON
|
||||||
const dataType = colType.toJSON()["DataType"];
|
const dataType = colType.toJSON()["DataType"];
|
||||||
return typeMapping[dataType] || "string";
|
return typeMapping[dataType] || "string";
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractDataFrame(df) {
|
function extractDataFrame(df) {
|
||||||
const fields = [];
|
const fields = [];
|
||||||
const schema = {
|
const schema = {
|
||||||
fields,
|
fields,
|
||||||
|
@ -172,43 +170,43 @@
|
||||||
"application/vnd.dataresource+json": { data, schema },
|
"application/vnd.dataresource+json": { data, schema },
|
||||||
"text/html": htmlTable,
|
"text/html": htmlTable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Canvas */
|
/** Canvas */
|
||||||
function isCanvasLike(obj) {
|
function isCanvasLike(obj) {
|
||||||
return obj !== null && typeof obj === "object" && "toDataURL" in obj;
|
return obj !== null && typeof obj === "object" && "toDataURL" in obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Possible HTML and SVG Elements */
|
/** Possible HTML and SVG Elements */
|
||||||
function isSVGElementLike(obj) {
|
function isSVGElementLike(obj) {
|
||||||
return obj !== null && typeof obj === "object" && "outerHTML" in obj &&
|
return obj !== null && typeof obj === "object" && "outerHTML" in obj &&
|
||||||
typeof obj.outerHTML === "string" && obj.outerHTML.startsWith("<svg");
|
typeof obj.outerHTML === "string" && obj.outerHTML.startsWith("<svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isHTMLElementLike(obj) {
|
function isHTMLElementLike(obj) {
|
||||||
return obj !== null && typeof obj === "object" && "outerHTML" in obj &&
|
return obj !== null && typeof obj === "object" && "outerHTML" in obj &&
|
||||||
typeof obj.outerHTML === "string";
|
typeof obj.outerHTML === "string";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check to see if an object already contains a `Symbol.for("Jupyter.display") */
|
/** Check to see if an object already contains a `Symbol.for("Jupyter.display") */
|
||||||
function hasDisplaySymbol(obj) {
|
function hasDisplaySymbol(obj) {
|
||||||
return obj !== null && typeof obj === "object" && $display in obj &&
|
return obj !== null && typeof obj === "object" && $display in obj &&
|
||||||
typeof obj[$display] === "function";
|
typeof obj[$display] === "function";
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeDisplayable(obj) {
|
function makeDisplayable(obj) {
|
||||||
return {
|
return {
|
||||||
[$display]: () => obj,
|
[$display]: () => obj,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format an object for displaying in Deno
|
* Format an object for displaying in Deno
|
||||||
*
|
*
|
||||||
* @param obj - The object to be displayed
|
* @param obj - The object to be displayed
|
||||||
* @returns MediaBundle
|
* @returns MediaBundle
|
||||||
*/
|
*/
|
||||||
async function format(obj) {
|
async function format(obj) {
|
||||||
if (hasDisplaySymbol(obj)) {
|
if (hasDisplaySymbol(obj)) {
|
||||||
return await obj[$display]();
|
return await obj[$display]();
|
||||||
}
|
}
|
||||||
|
@ -250,16 +248,16 @@
|
||||||
colors: !Deno.noColor,
|
colors: !Deno.noColor,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function creates a tagged template function for a given media type.
|
* This function creates a tagged template function for a given media type.
|
||||||
* The tagged template function takes a template string and returns a displayable object.
|
* The tagged template function takes a template string and returns a displayable object.
|
||||||
*
|
*
|
||||||
* @param mediatype - The media type for the tagged template function.
|
* @param mediatype - The media type for the tagged template function.
|
||||||
* @returns A function that takes a template string and returns a displayable object.
|
* @returns A function that takes a template string and returns a displayable object.
|
||||||
*/
|
*/
|
||||||
function createTaggedTemplateDisplayable(mediatype) {
|
function createTaggedTemplateDisplayable(mediatype) {
|
||||||
return (strings, ...values) => {
|
return (strings, ...values) => {
|
||||||
const payload = strings.reduce(
|
const payload = strings.reduce(
|
||||||
(acc, string, i) =>
|
(acc, string, i) =>
|
||||||
|
@ -268,9 +266,9 @@
|
||||||
);
|
);
|
||||||
return makeDisplayable({ [mediatype]: payload });
|
return makeDisplayable({ [mediatype]: payload });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show Markdown in Jupyter frontends with a tagged template function.
|
* Show Markdown in Jupyter frontends with a tagged template function.
|
||||||
*
|
*
|
||||||
* Takes a template string and returns a displayable object for Jupyter frontends.
|
* Takes a template string and returns a displayable object for Jupyter frontends.
|
||||||
|
@ -289,9 +287,9 @@
|
||||||
* `
|
* `
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
const md = createTaggedTemplateDisplayable("text/markdown");
|
const md = createTaggedTemplateDisplayable("text/markdown");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show HTML in Jupyter frontends with a tagged template function.
|
* Show HTML in Jupyter frontends with a tagged template function.
|
||||||
*
|
*
|
||||||
* Takes a template string and returns a displayable object for Jupyter frontends.
|
* Takes a template string and returns a displayable object for Jupyter frontends.
|
||||||
|
@ -302,8 +300,8 @@
|
||||||
* html`<h1>Hello, world!</h1>`
|
* html`<h1>Hello, world!</h1>`
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
const html = createTaggedTemplateDisplayable("text/html");
|
const html = createTaggedTemplateDisplayable("text/html");
|
||||||
/**
|
/**
|
||||||
* SVG Tagged Template Function.
|
* SVG Tagged Template Function.
|
||||||
*
|
*
|
||||||
* Takes a template string and returns a displayable object for Jupyter frontends.
|
* Takes a template string and returns a displayable object for Jupyter frontends.
|
||||||
|
@ -314,9 +312,9 @@
|
||||||
* <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
|
* <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
|
||||||
* </svg>`
|
* </svg>`
|
||||||
*/
|
*/
|
||||||
const svg = createTaggedTemplateDisplayable("image/svg+xml");
|
const svg = createTaggedTemplateDisplayable("image/svg+xml");
|
||||||
|
|
||||||
function isMediaBundle(obj) {
|
function isMediaBundle(obj) {
|
||||||
if (obj == null || typeof obj !== "object" || Array.isArray(obj)) {
|
if (obj == null || typeof obj !== "object" || Array.isArray(obj)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -326,19 +324,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function formatInner(obj, raw) {
|
async function formatInner(obj, raw) {
|
||||||
if (raw && isMediaBundle(obj)) {
|
if (raw && isMediaBundle(obj)) {
|
||||||
return obj;
|
return obj;
|
||||||
} else {
|
} else {
|
||||||
return await format(obj);
|
return await format(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internals.jupyter = { formatInner };
|
internals.jupyter = { formatInner };
|
||||||
|
|
||||||
function enableJupyter() {
|
function enableJupyter() {
|
||||||
const {
|
const {
|
||||||
op_jupyter_broadcast,
|
op_jupyter_broadcast,
|
||||||
} = core.ensureFastOps();
|
} = core.ensureFastOps();
|
||||||
|
@ -425,7 +423,6 @@
|
||||||
svg,
|
svg,
|
||||||
$display,
|
$display,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
internals.enableJupyter = enableJupyter;
|
internals.enableJupyter = enableJupyter;
|
||||||
})();
|
|
||||||
|
|
|
@ -1,38 +1,55 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
// Do not use primordials because we do not want to depend on the __bootstrap
|
|
||||||
// namespace.
|
|
||||||
//
|
|
||||||
// deno-lint-ignore-file
|
// deno-lint-ignore-file
|
||||||
(() => {
|
|
||||||
const internals = Deno[Deno.internal];
|
|
||||||
const core = internals.core;
|
|
||||||
const ops = core.ops;
|
|
||||||
|
|
||||||
const {
|
import { core, internals, primordials } from "ext:core/mod.js";
|
||||||
setExitHandler,
|
const ops = core.ops;
|
||||||
Console,
|
|
||||||
serializePermissions,
|
|
||||||
} = internals;
|
|
||||||
|
|
||||||
const opSanitizerDelayResolveQueue = [];
|
import { setExitHandler } from "ext:runtime/30_os.js";
|
||||||
let hasSetOpSanitizerDelayMacrotask = false;
|
import { Console } from "ext:deno_console/01_console.js";
|
||||||
|
import { serializePermissions } from "ext:runtime/10_permissions.js";
|
||||||
|
import { setTimeout } from "ext:deno_web/02_timers.js";
|
||||||
|
|
||||||
// Even if every resource is closed by the end of a test, there can be a delay
|
const {
|
||||||
// until the pending ops have all finished. This function returns a promise
|
ArrayPrototypeFilter,
|
||||||
// that resolves when it's (probably) fine to run the op sanitizer.
|
ArrayPrototypeJoin,
|
||||||
//
|
ArrayPrototypePush,
|
||||||
// This is implemented by adding a macrotask callback that runs after the
|
ArrayPrototypeShift,
|
||||||
// all ready async ops resolve, and the timer macrotask. Using just a macrotask
|
DateNow,
|
||||||
// callback without delaying is sufficient, because when the macrotask callback
|
Error,
|
||||||
// runs after async op dispatch, we know that all async ops that can currently
|
FunctionPrototype,
|
||||||
// return `Poll::Ready` have done so, and have been dispatched to JS.
|
Map,
|
||||||
//
|
MapPrototypeGet,
|
||||||
// Worker ops are an exception to this, because there is no way for the user to
|
MapPrototypeHas,
|
||||||
// await shutdown of the worker from the thread calling `worker.terminate()`.
|
MapPrototypeSet,
|
||||||
// Because of this, we give extra leeway for worker ops to complete, by waiting
|
MathCeil,
|
||||||
// for a whole millisecond if there are pending worker ops.
|
ObjectKeys,
|
||||||
function opSanitizerDelay(hasPendingWorkerOps) {
|
ObjectPrototypeIsPrototypeOf,
|
||||||
|
Promise,
|
||||||
|
SafeArrayIterator,
|
||||||
|
Set,
|
||||||
|
StringPrototypeReplaceAll,
|
||||||
|
SymbolToStringTag,
|
||||||
|
TypeError,
|
||||||
|
} = primordials;
|
||||||
|
|
||||||
|
const opSanitizerDelayResolveQueue = [];
|
||||||
|
let hasSetOpSanitizerDelayMacrotask = false;
|
||||||
|
|
||||||
|
// Even if every resource is closed by the end of a test, there can be a delay
|
||||||
|
// until the pending ops have all finished. This function returns a promise
|
||||||
|
// that resolves when it's (probably) fine to run the op sanitizer.
|
||||||
|
//
|
||||||
|
// This is implemented by adding a macrotask callback that runs after the
|
||||||
|
// all ready async ops resolve, and the timer macrotask. Using just a macrotask
|
||||||
|
// callback without delaying is sufficient, because when the macrotask callback
|
||||||
|
// runs after async op dispatch, we know that all async ops that can currently
|
||||||
|
// return `Poll::Ready` have done so, and have been dispatched to JS.
|
||||||
|
//
|
||||||
|
// Worker ops are an exception to this, because there is no way for the user to
|
||||||
|
// await shutdown of the worker from the thread calling `worker.terminate()`.
|
||||||
|
// Because of this, we give extra leeway for worker ops to complete, by waiting
|
||||||
|
// for a whole millisecond if there are pending worker ops.
|
||||||
|
function opSanitizerDelay(hasPendingWorkerOps) {
|
||||||
if (!hasSetOpSanitizerDelayMacrotask) {
|
if (!hasSetOpSanitizerDelayMacrotask) {
|
||||||
core.setMacrotaskCallback(handleOpSanitizerDelayMacrotask);
|
core.setMacrotaskCallback(handleOpSanitizerDelayMacrotask);
|
||||||
hasSetOpSanitizerDelayMacrotask = true;
|
hasSetOpSanitizerDelayMacrotask = true;
|
||||||
|
@ -43,25 +60,25 @@
|
||||||
// timeout callback will mean that the resolver gets called in the same
|
// timeout callback will mean that the resolver gets called in the same
|
||||||
// event loop tick as the timeout callback.
|
// event loop tick as the timeout callback.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
opSanitizerDelayResolveQueue.push(resolve);
|
ArrayPrototypePush(opSanitizerDelayResolveQueue, resolve);
|
||||||
}, hasPendingWorkerOps ? 1 : 0);
|
}, hasPendingWorkerOps ? 1 : 0);
|
||||||
});
|
});
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOpSanitizerDelayMacrotask() {
|
function handleOpSanitizerDelayMacrotask() {
|
||||||
const resolve = opSanitizerDelayResolveQueue.shift();
|
const resolve = ArrayPrototypeShift(opSanitizerDelayResolveQueue);
|
||||||
if (resolve) {
|
if (resolve) {
|
||||||
resolve();
|
resolve();
|
||||||
return opSanitizerDelayResolveQueue.length === 0;
|
return opSanitizerDelayResolveQueue.length === 0;
|
||||||
}
|
}
|
||||||
return undefined; // we performed no work, so can skip microtasks checkpoint
|
return undefined; // we performed no work, so can skip microtasks checkpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
// An async operation to $0 was started in this test, but never completed. This is often caused by not $1.
|
// An async operation to $0 was started in this test, but never completed. This is often caused by not $1.
|
||||||
// An async operation to $0 was started in this test, but never completed. Async operations should not complete in a test if they were not started in that test.
|
// An async operation to $0 was started in this test, but never completed. Async operations should not complete in a test if they were not started in that test.
|
||||||
// deno-fmt-ignore
|
// deno-fmt-ignore
|
||||||
const OP_DETAILS = {
|
const OP_DETAILS = {
|
||||||
"op_blob_read_part": ["read from a Blob or File", "awaiting the result of a Blob or File read"],
|
"op_blob_read_part": ["read from a Blob or File", "awaiting the result of a Blob or File read"],
|
||||||
"op_broadcast_recv": ["receive a message from a BroadcastChannel", "closing the BroadcastChannel"],
|
"op_broadcast_recv": ["receive a message from a BroadcastChannel", "closing the BroadcastChannel"],
|
||||||
"op_broadcast_send": ["send a message to a BroadcastChannel", "closing the BroadcastChannel"],
|
"op_broadcast_send": ["send a message to a BroadcastChannel", "closing the BroadcastChannel"],
|
||||||
|
@ -135,22 +152,22 @@
|
||||||
"op_ws_send_pong": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"],
|
"op_ws_send_pong": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"],
|
||||||
};
|
};
|
||||||
|
|
||||||
let opIdHostRecvMessage = -1;
|
let opIdHostRecvMessage = -1;
|
||||||
let opIdHostRecvCtrl = -1;
|
let opIdHostRecvCtrl = -1;
|
||||||
let opNames = null;
|
let opNames = null;
|
||||||
|
|
||||||
function populateOpNames() {
|
function populateOpNames() {
|
||||||
opNames = core.ops.op_op_names();
|
opNames = core.ops.op_op_names();
|
||||||
opIdHostRecvMessage = opNames.indexOf("op_host_recv_message");
|
opIdHostRecvMessage = opNames.indexOf("op_host_recv_message");
|
||||||
opIdHostRecvCtrl = opNames.indexOf("op_host_recv_ctrl");
|
opIdHostRecvCtrl = opNames.indexOf("op_host_recv_ctrl");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap test function in additional assertion that makes sure
|
// Wrap test function in additional assertion that makes sure
|
||||||
// the test case does not leak async "ops" - ie. number of async
|
// the test case does not leak async "ops" - ie. number of async
|
||||||
// completed ops after the test is the same as number of dispatched
|
// completed ops after the test is the same as number of dispatched
|
||||||
// ops. Note that "unref" ops are ignored since in nature that are
|
// ops. Note that "unref" ops are ignored since in nature that are
|
||||||
// optional.
|
// optional.
|
||||||
function assertOps(fn) {
|
function assertOps(fn) {
|
||||||
/** @param desc {TestDescription | TestStepDescription} */
|
/** @param desc {TestDescription | TestStepDescription} */
|
||||||
return async function asyncOpSanitizer(desc) {
|
return async function asyncOpSanitizer(desc) {
|
||||||
if (opNames === null) populateOpNames();
|
if (opNames === null) populateOpNames();
|
||||||
|
@ -219,17 +236,17 @@
|
||||||
const traces = [];
|
const traces = [];
|
||||||
for (const [id, { opName: traceOpName, stack }] of postTraces) {
|
for (const [id, { opName: traceOpName, stack }] of postTraces) {
|
||||||
if (traceOpName !== opName) continue;
|
if (traceOpName !== opName) continue;
|
||||||
if (preTraces.has(id)) continue;
|
if (MapPrototypeHas(preTraces, id)) continue;
|
||||||
traces.push(stack);
|
ArrayPrototypePush(traces, stack);
|
||||||
}
|
}
|
||||||
if (traces.length === 1) {
|
if (traces.length === 1) {
|
||||||
message += " The operation was started here:\n";
|
message += " The operation was started here:\n";
|
||||||
message += traces[0];
|
message += traces[0];
|
||||||
} else if (traces.length > 1) {
|
} else if (traces.length > 1) {
|
||||||
message += " The operations were started here:\n";
|
message += " The operations were started here:\n";
|
||||||
message += traces.join("\n\n");
|
message += ArrayPrototypeJoin(traces, "\n\n");
|
||||||
}
|
}
|
||||||
details.push(message);
|
ArrayPrototypePush(details, message);
|
||||||
} else if (diff < 0) {
|
} else if (diff < 0) {
|
||||||
const [name, hint] = OP_DETAILS[opName] || [opName, null];
|
const [name, hint] = OP_DETAILS[opName] || [opName, null];
|
||||||
const count = -diff;
|
const count = -diff;
|
||||||
|
@ -246,17 +263,17 @@
|
||||||
const traces = [];
|
const traces = [];
|
||||||
for (const [id, { opName: traceOpName, stack }] of preTraces) {
|
for (const [id, { opName: traceOpName, stack }] of preTraces) {
|
||||||
if (opName !== traceOpName) continue;
|
if (opName !== traceOpName) continue;
|
||||||
if (postTraces.has(id)) continue;
|
if (MapPrototypeHas(postTraces, id)) continue;
|
||||||
traces.push(stack);
|
ArrayPrototypePush(traces, stack);
|
||||||
}
|
}
|
||||||
if (traces.length === 1) {
|
if (traces.length === 1) {
|
||||||
message += " The operation was started here:\n";
|
message += " The operation was started here:\n";
|
||||||
message += traces[0];
|
message += traces[0];
|
||||||
} else if (traces.length > 1) {
|
} else if (traces.length > 1) {
|
||||||
message += " The operations were started here:\n";
|
message += " The operations were started here:\n";
|
||||||
message += traces.join("\n\n");
|
message += ArrayPrototypeJoin(traces, "\n\n");
|
||||||
}
|
}
|
||||||
details.push(message);
|
ArrayPrototypePush(details, message);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("unreachable");
|
throw new Error("unreachable");
|
||||||
}
|
}
|
||||||
|
@ -266,9 +283,9 @@
|
||||||
failed: { leakedOps: [details, core.isOpCallTracingEnabled()] },
|
failed: { leakedOps: [details, core.isOpCallTracingEnabled()] },
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function prettyResourceNames(name) {
|
function prettyResourceNames(name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "fsFile":
|
case "fsFile":
|
||||||
return ["A file", "opened", "closed"];
|
return ["A file", "opened", "closed"];
|
||||||
|
@ -333,9 +350,9 @@
|
||||||
default:
|
default:
|
||||||
return [`A "${name}" resource`, "created", "cleaned up"];
|
return [`A "${name}" resource`, "created", "cleaned up"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resourceCloseHint(name) {
|
function resourceCloseHint(name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "fsFile":
|
case "fsFile":
|
||||||
return "Close the file handle by calling `file.close()`.";
|
return "Close the file handle by calling `file.close()`.";
|
||||||
|
@ -400,12 +417,12 @@
|
||||||
default:
|
default:
|
||||||
return "Close the resource before the end of the test.";
|
return "Close the resource before the end of the test.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap test function in additional assertion that makes sure
|
// Wrap test function in additional assertion that makes sure
|
||||||
// the test case does not "leak" resources - ie. resource table after
|
// the test case does not "leak" resources - ie. resource table after
|
||||||
// the test has exactly the same contents as before the test.
|
// the test has exactly the same contents as before the test.
|
||||||
function assertResources(fn) {
|
function assertResources(fn) {
|
||||||
/** @param desc {TestDescription | TestStepDescription} */
|
/** @param desc {TestDescription | TestStepDescription} */
|
||||||
return async function resourceSanitizer(desc) {
|
return async function resourceSanitizer(desc) {
|
||||||
const pre = core.resources();
|
const pre = core.resources();
|
||||||
|
@ -414,8 +431,8 @@
|
||||||
const post = core.resources();
|
const post = core.resources();
|
||||||
|
|
||||||
const allResources = new Set([
|
const allResources = new Set([
|
||||||
...Object.keys(pre),
|
...new SafeArrayIterator(ObjectKeys(pre)),
|
||||||
...Object.keys(post),
|
...new SafeArrayIterator(ObjectKeys(post)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const details = [];
|
const details = [];
|
||||||
|
@ -429,12 +446,12 @@
|
||||||
const hint = resourceCloseHint(postResource);
|
const hint = resourceCloseHint(postResource);
|
||||||
const detail =
|
const detail =
|
||||||
`${name} (rid ${resource}) was ${action1} during the test, but not ${action2} during the test. ${hint}`;
|
`${name} (rid ${resource}) was ${action1} during the test, but not ${action2} during the test. ${hint}`;
|
||||||
details.push(detail);
|
ArrayPrototypePush(details, detail);
|
||||||
} else {
|
} else {
|
||||||
const [name, action1, action2] = prettyResourceNames(preResource);
|
const [name, action1, action2] = prettyResourceNames(preResource);
|
||||||
const detail =
|
const detail =
|
||||||
`${name} (rid ${resource}) was ${action1} before the test started, but was ${action2} during the test. Do not close resources in a test that were not created during that test.`;
|
`${name} (rid ${resource}) was ${action1} before the test started, but was ${action2} during the test. Do not close resources in a test that were not created during that test.`;
|
||||||
details.push(detail);
|
ArrayPrototypePush(details, detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (details.length == 0) {
|
if (details.length == 0) {
|
||||||
|
@ -442,11 +459,11 @@
|
||||||
}
|
}
|
||||||
return { failed: { leakedResources: details } };
|
return { failed: { leakedResources: details } };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap test function in additional assertion that makes sure
|
// Wrap test function in additional assertion that makes sure
|
||||||
// that the test case does not accidentally exit prematurely.
|
// that the test case does not accidentally exit prematurely.
|
||||||
function assertExit(fn, isTest) {
|
function assertExit(fn, isTest) {
|
||||||
return async function exitSanitizer(...params) {
|
return async function exitSanitizer(...params) {
|
||||||
setExitHandler((exitCode) => {
|
setExitHandler((exitCode) => {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -457,15 +474,15 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const innerResult = await fn(...params);
|
const innerResult = await fn(...new SafeArrayIterator(params));
|
||||||
if (innerResult) return innerResult;
|
if (innerResult) return innerResult;
|
||||||
} finally {
|
} finally {
|
||||||
setExitHandler(null);
|
setExitHandler(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapOuter(fn, desc) {
|
function wrapOuter(fn, desc) {
|
||||||
return async function outerWrapped() {
|
return async function outerWrapped() {
|
||||||
try {
|
try {
|
||||||
if (desc.ignore) {
|
if (desc.ignore) {
|
||||||
|
@ -475,30 +492,30 @@
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { failed: { jsError: core.destructureError(error) } };
|
return { failed: { jsError: core.destructureError(error) } };
|
||||||
} finally {
|
} finally {
|
||||||
const state = testStates.get(desc.id);
|
const state = MapPrototypeGet(testStates, desc.id);
|
||||||
for (const childDesc of state.children) {
|
for (const childDesc of state.children) {
|
||||||
stepReportResult(childDesc, { failed: "incomplete" }, 0);
|
stepReportResult(childDesc, { failed: "incomplete" }, 0);
|
||||||
}
|
}
|
||||||
state.completed = true;
|
state.completed = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapInner(fn) {
|
function wrapInner(fn) {
|
||||||
/** @param desc {TestDescription | TestStepDescription} */
|
/** @param desc {TestDescription | TestStepDescription} */
|
||||||
return async function innerWrapped(desc) {
|
return async function innerWrapped(desc) {
|
||||||
function getRunningStepDescs() {
|
function getRunningStepDescs() {
|
||||||
const results = [];
|
const results = [];
|
||||||
let childDesc = desc;
|
let childDesc = desc;
|
||||||
while (childDesc.parent != null) {
|
while (childDesc.parent != null) {
|
||||||
const state = testStates.get(childDesc.parent.id);
|
const state = MapPrototypeGet(testStates, childDesc.parent.id);
|
||||||
for (const siblingDesc of state.children) {
|
for (const siblingDesc of state.children) {
|
||||||
if (siblingDesc.id == childDesc.id) {
|
if (siblingDesc.id == childDesc.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const siblingState = testStates.get(siblingDesc.id);
|
const siblingState = MapPrototypeGet(testStates, siblingDesc.id);
|
||||||
if (!siblingState.completed) {
|
if (!siblingState.completed) {
|
||||||
results.push(siblingDesc);
|
ArrayPrototypePush(results, siblingDesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
childDesc = childDesc.parent;
|
childDesc = childDesc.parent;
|
||||||
|
@ -506,7 +523,8 @@
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
const runningStepDescs = getRunningStepDescs();
|
const runningStepDescs = getRunningStepDescs();
|
||||||
const runningStepDescsWithSanitizers = runningStepDescs.filter(
|
const runningStepDescsWithSanitizers = ArrayPrototypeFilter(
|
||||||
|
runningStepDescs,
|
||||||
(d) => usesSanitizer(d),
|
(d) => usesSanitizer(d),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -527,10 +545,10 @@
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
await fn(testStates.get(desc.id).context);
|
await fn(MapPrototypeGet(testStates, desc.id).context);
|
||||||
let failedSteps = 0;
|
let failedSteps = 0;
|
||||||
for (const childDesc of testStates.get(desc.id).children) {
|
for (const childDesc of MapPrototypeGet(testStates, desc.id).children) {
|
||||||
const state = testStates.get(childDesc.id);
|
const state = MapPrototypeGet(testStates, childDesc.id);
|
||||||
if (!state.completed) {
|
if (!state.completed) {
|
||||||
return { failed: "incompleteSteps" };
|
return { failed: "incompleteSteps" };
|
||||||
}
|
}
|
||||||
|
@ -540,51 +558,51 @@
|
||||||
}
|
}
|
||||||
return failedSteps == 0 ? null : { failed: { failedSteps } };
|
return failedSteps == 0 ? null : { failed: { failedSteps } };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function pledgePermissions(permissions) {
|
function pledgePermissions(permissions) {
|
||||||
return ops.op_pledge_test_permissions(
|
return ops.op_pledge_test_permissions(
|
||||||
serializePermissions(permissions),
|
serializePermissions(permissions),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function restorePermissions(token) {
|
function restorePermissions(token) {
|
||||||
ops.op_restore_test_permissions(token);
|
ops.op_restore_test_permissions(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
function withPermissions(fn, permissions) {
|
function withPermissions(fn, permissions) {
|
||||||
return async function applyPermissions(...params) {
|
return async function applyPermissions(...params) {
|
||||||
const token = pledgePermissions(permissions);
|
const token = pledgePermissions(permissions);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await fn(...params);
|
return await fn(...new SafeArrayIterator(params));
|
||||||
} finally {
|
} finally {
|
||||||
restorePermissions(token);
|
restorePermissions(token);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESCAPE_ASCII_CHARS = [
|
const ESCAPE_ASCII_CHARS = [
|
||||||
["\b", "\\b"],
|
["\b", "\\b"],
|
||||||
["\f", "\\f"],
|
["\f", "\\f"],
|
||||||
["\t", "\\t"],
|
["\t", "\\t"],
|
||||||
["\n", "\\n"],
|
["\n", "\\n"],
|
||||||
["\r", "\\r"],
|
["\r", "\\r"],
|
||||||
["\v", "\\v"],
|
["\v", "\\v"],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function escapeName(name) {
|
function escapeName(name) {
|
||||||
// Check if we need to escape a character
|
// Check if we need to escape a character
|
||||||
for (let i = 0; i < name.length; i++) {
|
for (let i = 0; i < name.length; i++) {
|
||||||
const ch = name.charCodeAt(i);
|
const ch = name.charCodeAt(i);
|
||||||
if (ch <= 13 && ch >= 8) {
|
if (ch <= 13 && ch >= 8) {
|
||||||
// Slow path: We do need to escape it
|
// Slow path: We do need to escape it
|
||||||
for (const [escape, replaceWith] of ESCAPE_ASCII_CHARS) {
|
for (const [escape, replaceWith] of ESCAPE_ASCII_CHARS) {
|
||||||
name = name.replaceAll(escape, replaceWith);
|
name = StringPrototypeReplaceAll(name, escape, replaceWith);
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -592,9 +610,9 @@
|
||||||
|
|
||||||
// We didn't need to escape anything, return original string
|
// We didn't need to escape anything, return original string
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* id: number,
|
* id: number,
|
||||||
* name: string,
|
* name: string,
|
||||||
|
@ -650,27 +668,27 @@
|
||||||
* }} BenchDescription
|
* }} BenchDescription
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @type {Map<number, TestState | TestStepState>} */
|
/** @type {Map<number, TestState | TestStepState>} */
|
||||||
const testStates = new Map();
|
const testStates = new Map();
|
||||||
/** @type {number | null} */
|
/** @type {number | null} */
|
||||||
let currentBenchId = null;
|
let currentBenchId = null;
|
||||||
// These local variables are used to track time measurements at
|
// These local variables are used to track time measurements at
|
||||||
// `BenchContext::{start,end}` calls. They are global instead of using a state
|
// `BenchContext::{start,end}` calls. They are global instead of using a state
|
||||||
// map to minimise the overhead of assigning them.
|
// map to minimise the overhead of assigning them.
|
||||||
/** @type {number | null} */
|
/** @type {number | null} */
|
||||||
let currentBenchUserExplicitStart = null;
|
let currentBenchUserExplicitStart = null;
|
||||||
/** @type {number | null} */
|
/** @type {number | null} */
|
||||||
let currentBenchUserExplicitEnd = null;
|
let currentBenchUserExplicitEnd = null;
|
||||||
|
|
||||||
const registerTestIdRetBuf = new Uint32Array(1);
|
const registerTestIdRetBuf = new Uint32Array(1);
|
||||||
const registerTestIdRetBufU8 = new Uint8Array(registerTestIdRetBuf.buffer);
|
const registerTestIdRetBufU8 = new Uint8Array(registerTestIdRetBuf.buffer);
|
||||||
|
|
||||||
function testInner(
|
function testInner(
|
||||||
nameOrFnOrOptions,
|
nameOrFnOrOptions,
|
||||||
optionsOrFn,
|
optionsOrFn,
|
||||||
maybeFn,
|
maybeFn,
|
||||||
overrides = {},
|
overrides = {},
|
||||||
) {
|
) {
|
||||||
if (typeof ops.op_register_test != "function") {
|
if (typeof ops.op_register_test != "function") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -776,42 +794,42 @@
|
||||||
);
|
);
|
||||||
testDesc.id = registerTestIdRetBuf[0];
|
testDesc.id = registerTestIdRetBuf[0];
|
||||||
testDesc.origin = origin;
|
testDesc.origin = origin;
|
||||||
testStates.set(testDesc.id, {
|
MapPrototypeSet(testStates, testDesc.id, {
|
||||||
context: createTestContext(testDesc),
|
context: createTestContext(testDesc),
|
||||||
children: [],
|
children: [],
|
||||||
completed: false,
|
completed: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main test function provided by Deno.
|
// Main test function provided by Deno.
|
||||||
function test(
|
function test(
|
||||||
nameOrFnOrOptions,
|
nameOrFnOrOptions,
|
||||||
optionsOrFn,
|
optionsOrFn,
|
||||||
maybeFn,
|
maybeFn,
|
||||||
) {
|
) {
|
||||||
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn);
|
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
test.ignore = function (nameOrFnOrOptions, optionsOrFn, maybeFn) {
|
test.ignore = function (nameOrFnOrOptions, optionsOrFn, maybeFn) {
|
||||||
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { ignore: true });
|
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { ignore: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
test.only = function (
|
test.only = function (
|
||||||
nameOrFnOrOptions,
|
nameOrFnOrOptions,
|
||||||
optionsOrFn,
|
optionsOrFn,
|
||||||
maybeFn,
|
maybeFn,
|
||||||
) {
|
) {
|
||||||
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { only: true });
|
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { only: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
let registeredWarmupBench = false;
|
let registeredWarmupBench = false;
|
||||||
|
|
||||||
// Main bench function provided by Deno.
|
// Main bench function provided by Deno.
|
||||||
function bench(
|
function bench(
|
||||||
nameOrFnOrOptions,
|
nameOrFnOrOptions,
|
||||||
optionsOrFn,
|
optionsOrFn,
|
||||||
maybeFn,
|
maybeFn,
|
||||||
) {
|
) {
|
||||||
if (typeof ops.op_register_bench != "function") {
|
if (typeof ops.op_register_bench != "function") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -923,16 +941,16 @@
|
||||||
const { id, origin } = ops.op_register_bench(benchDesc);
|
const { id, origin } = ops.op_register_bench(benchDesc);
|
||||||
benchDesc.id = id;
|
benchDesc.id = id;
|
||||||
benchDesc.origin = origin;
|
benchDesc.origin = origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareMeasurements(a, b) {
|
function compareMeasurements(a, b) {
|
||||||
if (a > b) return 1;
|
if (a > b) return 1;
|
||||||
if (a < b) return -1;
|
if (a < b) return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function benchStats(
|
function benchStats(
|
||||||
n,
|
n,
|
||||||
highPrecision,
|
highPrecision,
|
||||||
usedExplicitTimers,
|
usedExplicitTimers,
|
||||||
|
@ -940,22 +958,22 @@
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
all,
|
all,
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
n,
|
n,
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
p75: all[Math.ceil(n * (75 / 100)) - 1],
|
p75: all[MathCeil(n * (75 / 100)) - 1],
|
||||||
p99: all[Math.ceil(n * (99 / 100)) - 1],
|
p99: all[MathCeil(n * (99 / 100)) - 1],
|
||||||
p995: all[Math.ceil(n * (99.5 / 100)) - 1],
|
p995: all[MathCeil(n * (99.5 / 100)) - 1],
|
||||||
p999: all[Math.ceil(n * (99.9 / 100)) - 1],
|
p999: all[MathCeil(n * (99.9 / 100)) - 1],
|
||||||
avg: !highPrecision ? (avg / n) : Math.ceil(avg / n),
|
avg: !highPrecision ? (avg / n) : MathCeil(avg / n),
|
||||||
highPrecision,
|
highPrecision,
|
||||||
usedExplicitTimers,
|
usedExplicitTimers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function benchMeasure(timeBudget, fn, async, context) {
|
async function benchMeasure(timeBudget, fn, async, context) {
|
||||||
let n = 0;
|
let n = 0;
|
||||||
let avg = 0;
|
let avg = 0;
|
||||||
let wavg = 0;
|
let wavg = 0;
|
||||||
|
@ -1036,7 +1054,7 @@
|
||||||
n++;
|
n++;
|
||||||
avg += measuredTime;
|
avg += measuredTime;
|
||||||
budget -= totalTime;
|
budget -= totalTime;
|
||||||
all.push(measuredTime);
|
ArrayPrototypePush(all, measuredTime);
|
||||||
if (measuredTime < min) min = measuredTime;
|
if (measuredTime < min) min = measuredTime;
|
||||||
if (measuredTime > max) max = measuredTime;
|
if (measuredTime > max) max = measuredTime;
|
||||||
}
|
}
|
||||||
|
@ -1059,7 +1077,7 @@
|
||||||
n++;
|
n++;
|
||||||
avg += measuredTime;
|
avg += measuredTime;
|
||||||
budget -= totalTime;
|
budget -= totalTime;
|
||||||
all.push(measuredTime);
|
ArrayPrototypePush(all, measuredTime);
|
||||||
if (measuredTime < min) min = measuredTime;
|
if (measuredTime < min) min = measuredTime;
|
||||||
if (measuredTime > max) max = measuredTime;
|
if (measuredTime > max) max = measuredTime;
|
||||||
}
|
}
|
||||||
|
@ -1080,7 +1098,7 @@
|
||||||
|
|
||||||
n++;
|
n++;
|
||||||
avg += iterationTime;
|
avg += iterationTime;
|
||||||
all.push(iterationTime);
|
ArrayPrototypePush(all, iterationTime);
|
||||||
if (iterationTime < min) min = iterationTime;
|
if (iterationTime < min) min = iterationTime;
|
||||||
if (iterationTime > max) max = iterationTime;
|
if (iterationTime > max) max = iterationTime;
|
||||||
budget -= iterationTime * lowPrecisionThresholdInNs;
|
budget -= iterationTime * lowPrecisionThresholdInNs;
|
||||||
|
@ -1097,7 +1115,7 @@
|
||||||
|
|
||||||
n++;
|
n++;
|
||||||
avg += iterationTime;
|
avg += iterationTime;
|
||||||
all.push(iterationTime);
|
ArrayPrototypePush(all, iterationTime);
|
||||||
if (iterationTime < min) min = iterationTime;
|
if (iterationTime < min) min = iterationTime;
|
||||||
if (iterationTime > max) max = iterationTime;
|
if (iterationTime > max) max = iterationTime;
|
||||||
budget -= iterationTime * lowPrecisionThresholdInNs;
|
budget -= iterationTime * lowPrecisionThresholdInNs;
|
||||||
|
@ -1115,12 +1133,12 @@
|
||||||
max,
|
max,
|
||||||
all,
|
all,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param desc {BenchDescription} */
|
/** @param desc {BenchDescription} */
|
||||||
function createBenchContext(desc) {
|
function createBenchContext(desc) {
|
||||||
return {
|
return {
|
||||||
[Symbol.toStringTag]: "BenchContext",
|
[SymbolToStringTag]: "BenchContext",
|
||||||
name: desc.name,
|
name: desc.name,
|
||||||
origin: desc.origin,
|
origin: desc.origin,
|
||||||
start() {
|
start() {
|
||||||
|
@ -1149,10 +1167,10 @@
|
||||||
currentBenchUserExplicitEnd = end;
|
currentBenchUserExplicitEnd = end;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Wrap a user benchmark function in one which returns a structured result. */
|
/** Wrap a user benchmark function in one which returns a structured result. */
|
||||||
function wrapBenchmark(desc) {
|
function wrapBenchmark(desc) {
|
||||||
const fn = desc.fn;
|
const fn = desc.fn;
|
||||||
return async function outerWrapped() {
|
return async function outerWrapped() {
|
||||||
let token = null;
|
let token = null;
|
||||||
|
@ -1197,25 +1215,25 @@
|
||||||
if (token !== null) restorePermissions(token);
|
if (token !== null) restorePermissions(token);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function benchNow() {
|
function benchNow() {
|
||||||
return ops.op_bench_now();
|
return ops.op_bench_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFullName(desc) {
|
function getFullName(desc) {
|
||||||
if ("parent" in desc) {
|
if ("parent" in desc) {
|
||||||
return `${getFullName(desc.parent)} ... ${desc.name}`;
|
return `${getFullName(desc.parent)} ... ${desc.name}`;
|
||||||
}
|
}
|
||||||
return desc.name;
|
return desc.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function usesSanitizer(desc) {
|
function usesSanitizer(desc) {
|
||||||
return desc.sanitizeResources || desc.sanitizeOps || desc.sanitizeExit;
|
return desc.sanitizeResources || desc.sanitizeOps || desc.sanitizeExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stepReportResult(desc, result, elapsed) {
|
function stepReportResult(desc, result, elapsed) {
|
||||||
const state = testStates.get(desc.id);
|
const state = MapPrototypeGet(testStates, desc.id);
|
||||||
for (const childDesc of state.children) {
|
for (const childDesc of state.children) {
|
||||||
stepReportResult(childDesc, { failed: "incomplete" }, 0);
|
stepReportResult(childDesc, { failed: "incomplete" }, 0);
|
||||||
}
|
}
|
||||||
|
@ -1226,16 +1244,16 @@
|
||||||
} else {
|
} else {
|
||||||
ops.op_test_event_step_result_failed(desc.id, result.failed, elapsed);
|
ops.op_test_event_step_result_failed(desc.id, result.failed, elapsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param desc {TestDescription | TestStepDescription} */
|
/** @param desc {TestDescription | TestStepDescription} */
|
||||||
function createTestContext(desc) {
|
function createTestContext(desc) {
|
||||||
let parent;
|
let parent;
|
||||||
let level;
|
let level;
|
||||||
let rootId;
|
let rootId;
|
||||||
let rootName;
|
let rootName;
|
||||||
if ("parent" in desc) {
|
if ("parent" in desc) {
|
||||||
parent = testStates.get(desc.parent.id).context;
|
parent = MapPrototypeGet(testStates, desc.parent.id).context;
|
||||||
level = desc.level;
|
level = desc.level;
|
||||||
rootId = desc.rootId;
|
rootId = desc.rootId;
|
||||||
rootName = desc.rootName;
|
rootName = desc.rootName;
|
||||||
|
@ -1246,7 +1264,7 @@
|
||||||
rootName = desc.name;
|
rootName = desc.name;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
[Symbol.toStringTag]: "TestContext",
|
[SymbolToStringTag]: "TestContext",
|
||||||
/**
|
/**
|
||||||
* The current test name.
|
* The current test name.
|
||||||
*/
|
*/
|
||||||
|
@ -1264,7 +1282,7 @@
|
||||||
* @param maybeFn {((t: TestContext) => void | Promise<void>) | undefined}
|
* @param maybeFn {((t: TestContext) => void | Promise<void>) | undefined}
|
||||||
*/
|
*/
|
||||||
async step(nameOrFnOrOptions, maybeFn) {
|
async step(nameOrFnOrOptions, maybeFn) {
|
||||||
if (testStates.get(desc.id).completed) {
|
if (MapPrototypeGet(testStates, desc.id).completed) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Cannot run test step after parent scope has finished execution. " +
|
"Cannot run test step after parent scope has finished execution. " +
|
||||||
"Ensure any `.step(...)` calls are executed before their parent scope completes execution.",
|
"Ensure any `.step(...)` calls are executed before their parent scope completes execution.",
|
||||||
|
@ -1273,9 +1291,7 @@
|
||||||
|
|
||||||
let stepDesc;
|
let stepDesc;
|
||||||
if (typeof nameOrFnOrOptions === "string") {
|
if (typeof nameOrFnOrOptions === "string") {
|
||||||
if (
|
if (!(ObjectPrototypeIsPrototypeOf(FunctionPrototype, maybeFn))) {
|
||||||
!Object.prototype.isPrototypeOf.call(Function.prototype, maybeFn)
|
|
||||||
) {
|
|
||||||
throw new TypeError("Expected function for second argument.");
|
throw new TypeError("Expected function for second argument.");
|
||||||
}
|
}
|
||||||
stepDesc = {
|
stepDesc = {
|
||||||
|
@ -1331,30 +1347,31 @@
|
||||||
failed: false,
|
failed: false,
|
||||||
completed: false,
|
completed: false,
|
||||||
};
|
};
|
||||||
testStates.set(stepDesc.id, state);
|
MapPrototypeSet(testStates, stepDesc.id, state);
|
||||||
testStates.get(stepDesc.parent.id).children.push(
|
ArrayPrototypePush(
|
||||||
|
MapPrototypeGet(testStates, stepDesc.parent.id).children,
|
||||||
stepDesc,
|
stepDesc,
|
||||||
);
|
);
|
||||||
|
|
||||||
ops.op_test_event_step_wait(stepDesc.id);
|
ops.op_test_event_step_wait(stepDesc.id);
|
||||||
const earlier = Date.now();
|
const earlier = DateNow();
|
||||||
const result = await stepDesc.fn(stepDesc);
|
const result = await stepDesc.fn(stepDesc);
|
||||||
const elapsed = Date.now() - earlier;
|
const elapsed = DateNow() - earlier;
|
||||||
state.failed = !!result.failed;
|
state.failed = !!result.failed;
|
||||||
stepReportResult(stepDesc, result, elapsed);
|
stepReportResult(stepDesc, result, elapsed);
|
||||||
return result == "ok";
|
return result == "ok";
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap a user test function in one which returns a structured result.
|
* Wrap a user test function in one which returns a structured result.
|
||||||
* @template T {Function}
|
* @template T {Function}
|
||||||
* @param testFn {T}
|
* @param testFn {T}
|
||||||
* @param desc {TestDescription | TestStepDescription}
|
* @param desc {TestDescription | TestStepDescription}
|
||||||
* @returns {T}
|
* @returns {T}
|
||||||
*/
|
*/
|
||||||
function wrapTest(desc) {
|
function wrapTest(desc) {
|
||||||
let testFn = wrapInner(desc.fn);
|
let testFn = wrapInner(desc.fn);
|
||||||
if (desc.sanitizeOps) {
|
if (desc.sanitizeOps) {
|
||||||
testFn = assertOps(testFn);
|
testFn = assertOps(testFn);
|
||||||
|
@ -1369,8 +1386,7 @@
|
||||||
testFn = withPermissions(testFn, desc.permissions);
|
testFn = withPermissions(testFn, desc.permissions);
|
||||||
}
|
}
|
||||||
return wrapOuter(testFn, desc);
|
return wrapOuter(testFn, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
globalThis.Deno.bench = bench;
|
globalThis.Deno.bench = bench;
|
||||||
globalThis.Deno.test = test;
|
globalThis.Deno.test = test;
|
||||||
})();
|
|
||||||
|
|
|
@ -637,13 +637,13 @@ impl CliMainWorkerFactory {
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.shared.subcommand.needs_test() {
|
if self.shared.subcommand.needs_test() {
|
||||||
worker.js_runtime.execute_script_static(
|
worker.js_runtime.lazy_load_es_module_from_code(
|
||||||
"ext:cli/40_testing.js",
|
"ext:cli/40_testing.js",
|
||||||
include_str!("js/40_testing.js"),
|
deno_core::FastString::StaticAscii(include_str!("js/40_testing.js")),
|
||||||
)?;
|
)?;
|
||||||
worker.js_runtime.execute_script_static(
|
worker.js_runtime.lazy_load_es_module_from_code(
|
||||||
"ext:cli/40_jupyter.js",
|
"ext:cli/40_jupyter.js",
|
||||||
include_str!("js/40_jupyter.js"),
|
deno_core::FastString::StaticAscii(include_str!("js/40_jupyter.js")),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
import { core, internals, primordials } from "ext:core/mod.js";
|
import { core, primordials } from "ext:core/mod.js";
|
||||||
const ops = core.ops;
|
const ops = core.ops;
|
||||||
import { pathFromURL } from "ext:deno_web/00_infra.js";
|
import { pathFromURL } from "ext:deno_web/00_infra.js";
|
||||||
import { Event, EventTarget } from "ext:deno_web/02_event.js";
|
import { Event, EventTarget } from "ext:deno_web/02_event.js";
|
||||||
|
@ -290,6 +290,4 @@ function serializePermissions(permissions) {
|
||||||
return permissions;
|
return permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
internals.serializePermissions = serializePermissions;
|
|
||||||
|
|
||||||
export { Permissions, permissions, PermissionStatus, serializePermissions };
|
export { Permissions, permissions, PermissionStatus, serializePermissions };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
import { core, internals, primordials } from "ext:core/mod.js";
|
import { core, primordials } from "ext:core/mod.js";
|
||||||
const ops = core.ops;
|
const ops = core.ops;
|
||||||
import { Event, EventTarget } from "ext:deno_web/02_event.js";
|
import { Event, EventTarget } from "ext:deno_web/02_event.js";
|
||||||
const {
|
const {
|
||||||
|
@ -105,8 +105,6 @@ function execPath() {
|
||||||
return ops.op_exec_path();
|
return ops.op_exec_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
internals.setExitHandler = setExitHandler;
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
env,
|
env,
|
||||||
execPath,
|
execPath,
|
||||||
|
|
|
@ -43,7 +43,6 @@ use deno_fs::FileSystem;
|
||||||
use deno_http::DefaultHttpPropertyExtractor;
|
use deno_http::DefaultHttpPropertyExtractor;
|
||||||
use deno_io::Stdio;
|
use deno_io::Stdio;
|
||||||
use deno_kv::dynamic::MultiBackendDbHandler;
|
use deno_kv::dynamic::MultiBackendDbHandler;
|
||||||
use deno_node::SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX;
|
|
||||||
use deno_tls::RootCertStoreProvider;
|
use deno_tls::RootCertStoreProvider;
|
||||||
use deno_web::create_entangled_message_port;
|
use deno_web::create_entangled_message_port;
|
||||||
use deno_web::BlobStore;
|
use deno_web::BlobStore;
|
||||||
|
@ -523,11 +522,6 @@ impl WebWorker {
|
||||||
(None, None)
|
(None, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clear extension modules from the module map, except preserve `node:*`
|
|
||||||
// modules as `node:` specifiers.
|
|
||||||
let preserve_snapshotted_modules =
|
|
||||||
Some(SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX);
|
|
||||||
|
|
||||||
let mut js_runtime = JsRuntime::new(RuntimeOptions {
|
let mut js_runtime = JsRuntime::new(RuntimeOptions {
|
||||||
module_loader: Some(options.module_loader.clone()),
|
module_loader: Some(options.module_loader.clone()),
|
||||||
startup_snapshot: options
|
startup_snapshot: options
|
||||||
|
@ -539,7 +533,6 @@ impl WebWorker {
|
||||||
compiled_wasm_module_store: options.compiled_wasm_module_store.clone(),
|
compiled_wasm_module_store: options.compiled_wasm_module_store.clone(),
|
||||||
extensions,
|
extensions,
|
||||||
inspector: options.maybe_inspector_server.is_some(),
|
inspector: options.maybe_inspector_server.is_some(),
|
||||||
preserve_snapshotted_modules,
|
|
||||||
feature_checker: Some(options.feature_checker.clone()),
|
feature_checker: Some(options.feature_checker.clone()),
|
||||||
op_metrics_factory_fn,
|
op_metrics_factory_fn,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -39,7 +39,6 @@ use deno_fs::FileSystem;
|
||||||
use deno_http::DefaultHttpPropertyExtractor;
|
use deno_http::DefaultHttpPropertyExtractor;
|
||||||
use deno_io::Stdio;
|
use deno_io::Stdio;
|
||||||
use deno_kv::dynamic::MultiBackendDbHandler;
|
use deno_kv::dynamic::MultiBackendDbHandler;
|
||||||
use deno_node::SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX;
|
|
||||||
use deno_tls::RootCertStoreProvider;
|
use deno_tls::RootCertStoreProvider;
|
||||||
use deno_web::BlobStore;
|
use deno_web::BlobStore;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
@ -420,11 +419,6 @@ impl MainWorker {
|
||||||
#[cfg(all(feature = "include_js_files_for_snapshotting", feature = "dont_create_runtime_snapshot", not(feature = "__runtime_js_sources")))]
|
#[cfg(all(feature = "include_js_files_for_snapshotting", feature = "dont_create_runtime_snapshot", not(feature = "__runtime_js_sources")))]
|
||||||
options.startup_snapshot.as_ref().expect("Sources are not embedded, snapshotting was disabled and a user snapshot was not provided.");
|
options.startup_snapshot.as_ref().expect("Sources are not embedded, snapshotting was disabled and a user snapshot was not provided.");
|
||||||
|
|
||||||
// Clear extension modules from the module map, except preserve `node:*`
|
|
||||||
// modules.
|
|
||||||
let preserve_snapshotted_modules =
|
|
||||||
Some(SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX);
|
|
||||||
|
|
||||||
let mut js_runtime = JsRuntime::new(RuntimeOptions {
|
let mut js_runtime = JsRuntime::new(RuntimeOptions {
|
||||||
module_loader: Some(options.module_loader.clone()),
|
module_loader: Some(options.module_loader.clone()),
|
||||||
startup_snapshot: options
|
startup_snapshot: options
|
||||||
|
@ -437,7 +431,6 @@ impl MainWorker {
|
||||||
shared_array_buffer_store: options.shared_array_buffer_store.clone(),
|
shared_array_buffer_store: options.shared_array_buffer_store.clone(),
|
||||||
compiled_wasm_module_store: options.compiled_wasm_module_store.clone(),
|
compiled_wasm_module_store: options.compiled_wasm_module_store.clone(),
|
||||||
extensions,
|
extensions,
|
||||||
preserve_snapshotted_modules,
|
|
||||||
inspector: options.maybe_inspector_server.is_some(),
|
inspector: options.maybe_inspector_server.is_some(),
|
||||||
is_main: true,
|
is_main: true,
|
||||||
feature_checker: Some(options.feature_checker.clone()),
|
feature_checker: Some(options.feature_checker.clone()),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue