import { Float16Array } from '../../external/petamoriken/float16/float16.js'; import { SkipTestCase } from '../framework/fixture.js'; import { globalTestConfig } from '../framework/test_config.js';
import { keysOf } from './data_tables.js'; import { timeout } from './timeout.js';
/** * Error with arbitrary `extra` data attached, for debugging. * The extra data is omitted if not running the test in debug mode (`?debug=1`).
*/
export class ErrorWithExtra extends Error {
readonly extra: { [k: string]: unknown };
/** * `extra` function is only called if in debug mode. * If an `ErrorWithExtra` is passed, its message is used and its extras are passed through.
*/
constructor(message: string, extra: () => {});
constructor(base: ErrorWithExtra, newExtra: () => {});
constructor(baseOrMessage: string | ErrorWithExtra, newExtra: () => {}) { const message = typeof baseOrMessage === 'string' ? baseOrMessage : baseOrMessage.message; super(message);
/** * Asserts `condition` is true. Otherwise, throws an `Error` with the provided message.
*/
export functionassert(condition: boolean, msg?: string | (() => string)): asserts condition { if (!condition) { thrownew Error(msg && (typeof msg === 'string' ? msg : msg()));
}
}
/** If the argument is an Error, throw it. Otherwise, pass it back. */
export function assertOK<T>(value: Error | T): T { if (value instanceof Error) { throw value;
} return value;
}
/** Options for assertReject, shouldReject, and friends. */
export type ExceptionCheckOptions = { allowMissingStack?: boolean; message?: string };
/** * Resolves if the provided promise rejects; rejects if it does not.
*/
export async function assertReject(
expectedName: string,
p: Promise<unknown>,
{ allowMissingStack = false, message }: ExceptionCheckOptions = {}
): Promise<void> { try {
await p;
unreachable(message);
} catch (ex) { // Asserted as expected if (!allowMissingStack) { const m = message ? ` (${message})` : ''; assert(
ex instanceof Error && typeof ex.stack === 'string', 'threw as expected, but missing stack' + m
);
}
}
}
/** * Assert this code is unreachable. Unconditionally throws an `Error`.
*/
export function unreachable(msg?: string): never { thrownew Error(msg);
}
/** * Throw a `SkipTestCase` exception, which skips the test case.
*/
export function skipTestCase(msg: string): never { thrownew SkipTestCase(msg);
}
/** * The `performance` interface. * It is available in all browsers, but it is not in scope by default in Node.
*/ /* eslint-disable-next-line n/no-restricted-require */ const perf = typeof performance !== 'undefined' ? performance : require('perf_hooks').performance;
/** * Calls the appropriate `performance.now()` depending on whether running in a browser or Node.
*/
export function now(): number { return perf.now();
}
/** * Returns a promise which resolves after the specified time.
*/
export function resolveOnTimeout(ms: number): Promise<void> { returnnew Promise(resolve => {
timeout(() => {
resolve();
}, ms);
});
}
export class PromiseTimeoutError extends Error {}
/** * Returns a promise which rejects after the specified time.
*/
export function rejectOnTimeout(ms: number, msg: string): Promise<never> { returnnew Promise((_resolve, reject) => {
timeout(() => {
reject(new PromiseTimeoutError(msg));
}, ms);
});
}
/** * Takes a promise `p`, and returns a new one which rejects if `p` takes too long, * and otherwise passes the result through.
*/
export function raceWithRejectOnTimeout<T>(p: Promise<T>, ms: number, msg: string): Promise<T> { if (globalTestConfig.noRaceWithRejectOnTimeout) { return p;
} // Setup a promise that will reject after `ms` milliseconds. We cancel this timeout when // `p` is finalized, so the JavaScript VM doesn't hang around waiting for the timer to // complete, once the test runner has finished executing the tests. const timeoutPromise = new Promise((_resolve, reject) => { const handle = timeout(() => {
reject(new PromiseTimeoutError(msg));
}, ms);
p = p.finally(() => clearTimeout(handle));
}); return Promise.race([p, timeoutPromise]) as Promise<T>;
}
/** * Takes a promise `p` and returns a new one which rejects if `p` resolves or rejects, * and otherwise resolves after the specified time.
*/
export function assertNotSettledWithinTime(
p: Promise<unknown>,
ms: number,
msg: string
): Promise<undefined> { // Rejects regardless of whether p resolves or rejects. const rejectWhenSettled = p.then(() => Promise.reject(new Error(msg))); // Resolves after `ms` milliseconds. const timeoutPromise = new Promise<undefined>(resolve => { const handle = timeout(() => {
resolve(undefined);
}, ms); void p.finally(() => clearTimeout(handle));
}); return Promise.race([rejectWhenSettled, timeoutPromise]);
}
/** * Returns a `Promise.reject()`, but also registers a dummy `.catch()` handler so it doesn't count * as an uncaught promise rejection in the runtime.
*/
export function rejectWithoutUncaught<T>(err: unknown): Promise<T> { const p = Promise.reject(err); // Suppress uncaught promise rejection.
p.catch(() => {}); return p;
}
/** * Returns true if v is a plain JavaScript object.
*/
export function isPlainObject(v: unknown) { return !!v && Object.getPrototypeOf(v).constructor === Object.prototype.constructor;
}
/** * Makes a copy of a JS `object`, with the keys reordered into sorted order.
*/
export function sortObjectByKey(v: { [k: string]: unknown }): { [k: string]: unknown } { const sortedObject: { [k: string]: unknown } = {}; for (const k of Object.keys(v).sort()) {
sortedObject[k] = v[k];
} return sortedObject;
}
/** * Determines whether two JS values are equal, recursing into objects and arrays. * NaN is treated specially, such that `objectEquals(NaN, NaN)`. +/-0.0 are treated as equal * by default, but can be opted to be distinguished. * @param x the first JS values that get compared * @param y the second JS values that get compared * @param distinguishSignedZero if set to true, treat 0.0 and -0.0 as unequal. Default to false.
*/
export function objectEquals(
x: unknown,
y: unknown,
distinguishSignedZero: boolean = false
): boolean { if (typeof x !== 'object' || typeof y !== 'object') { if (typeof x === 'number' && typeof y === 'number' && Number.isNaN(x) && Number.isNaN(y)) { returntrue;
} // Object.is(0.0, -0.0) is false while (0.0 === -0.0) is true. Other than +/-0.0 and NaN cases, // Object.is works in the same way as ===. return distinguishSignedZero ? Object.is(x, y) : x === y;
} if (x === null || y === null) return x === y; if (x.constructor !== y.constructor) returnfalse; if (x instanceofFunction) return x === y; if (x instanceof RegExp) return x === y; if (x === y || x.valueOf() === y.valueOf()) returntrue; if (Array.isArray(x) && Array.isArray(y) && x.length !== y.length) returnfalse; if (x instanceof Date) returnfalse; if (!(x instanceof Object)) returnfalse; if (!(y instanceof Object)) returnfalse;
const x1 = x as { [k: string]: unknown }; const y1 = y as { [k: string]: unknown }; const p = Object.keys(x); return Object.keys(y).every(i => p.indexOf(i) !== -1) && p.every(i => objectEquals(x1[i], y1[i]));
}
/** * Generates a range of values `fn(0)..fn(n-1)`.
*/
export function range<T>(n: number, fn: (i: number) => T): T[] { return [...new Array(n)].map((_, i) => fn(i));
}
/** * Generates a range of values `fn(0)..fn(n-1)`.
*/
export function* iterRange<T>(n: number, fn: (i: number) => T): Iterable<T> { for (let i = 0; i < n; ++i) {
yield fn(i);
}
}
/** Creates a (reusable) iterable object that maps `f` over `xs`, lazily. */
export function mapLazy<T, R>(xs: Iterable<T>, f: (x: T) => R): Iterable<R> { return {
*[Symbol.iterator]() { for (const x of xs) {
yield f(x);
}
},
};
}
/** * Creates a new array from the given array with the first half * swapped with the last half.
*/
export function shiftByHalf<R>(arr: R[]): R[] { const len = arr.length; const half = (len / 2) | 0; const firstHalf = arr.splice(0, half); return [...arr, ...firstHalf];
}
/** * Creates a reordered array from the input array based on the Order
*/
export function reorder<R>(order: ReorderOrder, arr: R[]): R[] { switch (order) { case'forward': return arr.slice(); case'backward': return arr.slice().reverse(); case'shiftByHalf': { // should this be pseudo random? return shiftByHalf(arr);
}
}
}
const TypedArrayBufferViewInstances = [ new Uint8Array(), new Uint8ClampedArray(), new Uint16Array(), new Uint32Array(), new Int8Array(), new Int16Array(), new Int32Array(), new Float16Array(), new Float32Array(), new Float64Array(), new BigInt64Array(), new BigUint64Array(),
] as const;
export type TypedArrayBufferView = (typeof TypedArrayBufferViewInstances)[number];
export type TypedArrayBufferViewConstructor<A extends TypedArrayBufferView = TypedArrayBufferView> =
{ // Interface copied from Uint8Array, and made generic.
readonly prototype: A;
readonly BYTES_PER_ELEMENT: number;
new (): A; new (elements: Iterable<number>): A; new (array: ArrayLike<number> | ArrayBufferLike): A; new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): A; new (length: number): A;
/** * Creates a case parameter for a typedarray. * * You can't put typedarrays in case parameters directly so instead of * * ``` * u.combine('data', [ * new Uint8Array([1, 2, 3]), * new Float32Array([4, 5, 6]), * ]) * ``` * * You can use * * ``` * u.combine('data', [ * typedArrayParam('Uint8Array' [1, 2, 3]), * typedArrayParam('Float32Array' [4, 5, 6]), * ]) * ``` * * and then convert the params to typedarrays eg. * * ``` * .fn(t => { * const data = t.params.data.map(v => typedArrayFromParam(v)); * }) * ```
*/
export function typedArrayParam<K extends keyof TypedArrayMap>(
type: K,
data: number[]
): TypedArrayParam<K> { return { type, data };
}
export function createTypedArray<K extends keyof TypedArrayMap>(
type: K,
data: readonly number[]
): TypedArrayMap[K] { returnnew kTypedArrayBufferViews[type](data) as TypedArrayMap[K];
}
/** * Converts a TypedArrayParam to a typedarray. See typedArrayParam
*/
export function typedArrayFromParam<K extends keyof TypedArrayMap>(
param: TypedArrayParam<K>
): TypedArrayMap[K] { const { type, data } = param; return createTypedArray(type, data);
}
function subarrayAsU8(
buf: ArrayBuffer | TypedArrayBufferView,
{ start = 0, length }: { start?: number; length?: number }
): Uint8Array | Uint8ClampedArray { if (buf instanceof ArrayBuffer) { returnnew Uint8Array(buf, start, length);
} elseif (buf instanceof Uint8Array || buf instanceof Uint8ClampedArray) { // Don't wrap in new views if we don't need to. if (start === 0 && (length === undefined || length === buf.byteLength)) { return buf;
}
} const byteOffset = buf.byteOffset + start * buf.BYTES_PER_ELEMENT; const byteLength =
length !== undefined
? length * buf.BYTES_PER_ELEMENT
: buf.byteLength - (byteOffset - buf.byteOffset); returnnew Uint8Array(buf.buffer, byteOffset, byteLength);
}
/** * Copy a range of bytes from one ArrayBuffer or TypedArray to another. * * `start`/`length` are in elements (or in bytes, if ArrayBuffer).
*/
export function memcpy(
src: { src: ArrayBuffer | TypedArrayBufferView; start?: number; length?: number },
dst: { dst: ArrayBuffer | TypedArrayBufferView; start?: number }
): void {
subarrayAsU8(dst.dst, dst).set(subarrayAsU8(src.src, src));
}
/** * Used to create a value that is specified by multiplying some runtime value * by a constant and then adding a constant to it.
*/
export interface ValueTestVariant {
mult: number;
add: number;
}
/** * Filters out SpecValues that are the same.
*/
export function filterUniqueValueTestVariants(valueTestVariants: ValueTestVariant[]) { returnnew Map<string, ValueTestVariant>(
valueTestVariants.map(v => [`m:${v.mult},a:${v.add}`, v])
).values();
}
/** * Used to create a value that is specified by multiplied some runtime value * by a constant and then adding a constant to it. This happens often in test * with limits that can only be known at runtime and yet we need a way to * add parameters to a test and those parameters must be constants.
*/
export function makeValueTestVariant(base: number, variant: ValueTestVariant) { return base * variant.mult + variant.add;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-04)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.