mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 13:21:55 +00:00
Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import {
|
||||
Agent, evalQ, Get, isPromiseObject, JSStringValue, ManagedRealm, NormalCompletion, setSurroundingAgent,
|
||||
skipDebugger,
|
||||
ThrowCompletion,
|
||||
unwrapCompletion,
|
||||
Value,
|
||||
type PromiseObject,
|
||||
} from '#self';
|
||||
|
||||
test('WeakRef (script)', () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`
|
||||
const w = new WeakRef({});
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
if (typeof w.deref() !== 'object') {
|
||||
throw new Error();
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
if (typeof w.deref() !== 'undefined') {
|
||||
throw new Error();
|
||||
}
|
||||
})
|
||||
.then(() => 'pass');
|
||||
`) as NormalCompletion<PromiseObject>;
|
||||
expect(result).toBeInstanceOf(NormalCompletion);
|
||||
expect(isPromiseObject(result.Value)).toBe(true);
|
||||
expect(result.Value.PromiseState).toBe('fulfilled');
|
||||
if (!(result.Value.PromiseResult instanceof JSStringValue)) {
|
||||
throw new Error('Expected JSStringValue');
|
||||
}
|
||||
expect(result.Value.PromiseResult.stringValue()).toBe('pass');
|
||||
});
|
||||
|
||||
test('WeakRef (module)', () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
realm.scope(() => {
|
||||
const module = realm.compileModule(`
|
||||
const w = new WeakRef({});
|
||||
globalThis.result = Promise.resolve()
|
||||
.then(() => {
|
||||
if (typeof w.deref() !== 'object') {
|
||||
throw new Error('should be object');
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
if (typeof w.deref() !== 'undefined') {
|
||||
throw new Error('should be undefined');
|
||||
}
|
||||
})
|
||||
.then(() => 'pass');
|
||||
`, { specifier: 'test.mjs' });
|
||||
if (module instanceof ThrowCompletion) {
|
||||
throw new Error('Module compilation failed');
|
||||
}
|
||||
const completion = evalQ((_Q, X) => {
|
||||
const m = X(module);
|
||||
m.LoadRequestedModules();
|
||||
X(m.Link());
|
||||
skipDebugger(m.Evaluate());
|
||||
const result = X(skipDebugger(Get(realm.GlobalObject, Value('result')))) as PromiseObject;
|
||||
expect(isPromiseObject(result)).toBe(true);
|
||||
expect(result.PromiseState).toBe('fulfilled');
|
||||
if (!(result.PromiseResult instanceof JSStringValue)) {
|
||||
throw new Error('Expected JSStringValue');
|
||||
}
|
||||
expect(result.PromiseResult.stringValue()).toBe('pass');
|
||||
});
|
||||
unwrapCompletion(completion);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable quotes */
|
||||
import { expect, test } from 'vitest';
|
||||
import {
|
||||
Agent, evalQ, ManagedRealm, NormalCompletion, NumberValue, R, setSurroundingAgent,
|
||||
surroundingAgent,
|
||||
UndefinedValue,
|
||||
Value,
|
||||
type ValueCompletion,
|
||||
} from '#self';
|
||||
|
||||
test('debugger statement should return undefined when no debugger is attached', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript('debugger;') as NormalCompletion<UndefinedValue>;
|
||||
expect(result).toBeInstanceOf(NormalCompletion);
|
||||
expect(result.Value).toBe(Value.undefined);
|
||||
});
|
||||
|
||||
test('debugger statement should return the value passed to resumeEvaluate', async () => {
|
||||
const agent = new Agent({
|
||||
onDebugger() {
|
||||
},
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
evalQ((_Q, X) => {
|
||||
const script = X(realm.compileScript('debugger;'));
|
||||
let completion!: ValueCompletion;
|
||||
realm.evaluate(script, (c) => {
|
||||
completion = c;
|
||||
});
|
||||
// start the evaluation
|
||||
X(surroundingAgent.resumeEvaluate({}));
|
||||
// paused at the debugger statement, resume with a value
|
||||
X(surroundingAgent.resumeEvaluate({
|
||||
debuggerStatementCompletion: NormalCompletion(Value(42)),
|
||||
}));
|
||||
expect(completion).toBeDefined();
|
||||
const value = X(completion) as NumberValue;
|
||||
expect(value).toBeInstanceOf(NumberValue);
|
||||
expect(R(value)).toBe(42);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import {
|
||||
Agent, isPromiseObject, JSStringValue, ManagedRealm, NormalCompletion, setSurroundingAgent,
|
||||
type PromiseObject,
|
||||
} from '#self';
|
||||
|
||||
test('stack', () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`
|
||||
function x() { throw new Error('owo'); }
|
||||
function y() { x(); }
|
||||
try {
|
||||
y();
|
||||
} catch (e) {
|
||||
e.stack;
|
||||
}
|
||||
`) as NormalCompletion<JSStringValue>;
|
||||
expect(result).toBeInstanceOf(NormalCompletion);
|
||||
expect(result.Value).toBeInstanceOf(JSStringValue);
|
||||
expect(result.Value.stringValue()).toMatchInlineSnapshot(`
|
||||
"Error: owo
|
||||
at x (<anonymous>:2:36)
|
||||
at y (<anonymous>:3:20)
|
||||
at <anonymous>:5:7"
|
||||
`);
|
||||
});
|
||||
|
||||
test('async stack', () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`
|
||||
async function x() { await 1; throw new Error('owo'); }
|
||||
async function y() { await x(); }
|
||||
y().catch((e) => e.stack);
|
||||
`) as NormalCompletion<PromiseObject>;
|
||||
expect(result).toBeInstanceOf(NormalCompletion);
|
||||
expect(isPromiseObject(result.Value)).toBe(true);
|
||||
expect(result.Value.PromiseState).toBe('fulfilled');
|
||||
if (!(result.Value.PromiseResult instanceof JSStringValue)) {
|
||||
throw new Error('Expected JSStringValue');
|
||||
}
|
||||
expect(result.Value.PromiseResult.stringValue()).toMatchInlineSnapshot(`
|
||||
"Error: owo
|
||||
at async x (<anonymous>:2:51)
|
||||
at async y (<anonymous>:3:32)"
|
||||
`);
|
||||
});
|
||||
|
||||
test('native stack', () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
const result = realm.evaluateScript(`
|
||||
function x() { Reflect.get(); }
|
||||
try {
|
||||
x();
|
||||
} catch (e) {
|
||||
e.stack;
|
||||
}
|
||||
`) as NormalCompletion<JSStringValue>;
|
||||
expect(result).toBeInstanceOf(NormalCompletion);
|
||||
expect(result.Value).toBeInstanceOf(JSStringValue);
|
||||
expect(result.Value.stringValue()).toMatchInlineSnapshot(`
|
||||
"TypeError: undefined is not an object
|
||||
at get (native)
|
||||
at x (<anonymous>:2:20)
|
||||
at <anonymous>:4:7"
|
||||
`);
|
||||
});
|
||||
@@ -0,0 +1,119 @@
|
||||
import { assert, expect, test } from 'vitest';
|
||||
import {
|
||||
AbstractModuleRecord, Agent, Call, JSStringValue, ManagedRealm, NewPromiseCapability, NormalCompletion, PromiseCapabilityRecord, setSurroundingAgent, skipDebugger, Value, type PromiseObject,
|
||||
} from '#self';
|
||||
|
||||
test('Import attributes', () => {
|
||||
let attributes!: Map<string, string>;
|
||||
let calls = 0;
|
||||
|
||||
const agent = new Agent({
|
||||
supportedImportAttributes: ['fruit', 'animal'],
|
||||
loadImportedModule: (_referrer, _specifier, attrs, _hostDefined, finish) => {
|
||||
calls += 1;
|
||||
attributes = attrs;
|
||||
finish(realm.compileModule(''));
|
||||
},
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
const realm = new ManagedRealm();
|
||||
|
||||
realm.evaluateModule('import "test" with {}', 'case 1');
|
||||
expect([...attributes]).lengthOf(0);
|
||||
|
||||
realm.evaluateModule('import "test" with { fruit: "banana" }', 'case 2');
|
||||
expect([...attributes]).deep.equal([['fruit', 'banana']]);
|
||||
|
||||
realm.evaluateModule('import "test" with { fruit: "banana", animal: "monkey" }', 'case 3');
|
||||
expect([...attributes]).deep.equal([['animal', 'monkey'], ['fruit', 'banana']]);
|
||||
|
||||
realm.evaluateModule('import "test" with { animal: "monkey", fruit: "banana" }', 'case 4');
|
||||
expect([...attributes]).deep.equal([['animal', 'monkey'], ['fruit', 'banana']]);
|
||||
|
||||
calls = 0;
|
||||
realm.evaluateModule('import "test" with { fruit: "banana" }; import "test" with { fruit: "banana" }', 'case 5');
|
||||
expect(calls).toBe(1);
|
||||
|
||||
calls = 0;
|
||||
realm.evaluateModule('import "test" with { fruit: "banana" }; import "test" with { animal: "monkey" }', 'case 6');
|
||||
expect(calls).toBe(2);
|
||||
|
||||
calls = 0;
|
||||
realm.evaluateModule('import "test" with { fruit: "banana", animal: "monkey" }; import "test" with { animal: "monkey", fruit: "banana" };', 'case 7');
|
||||
expect(calls).toBe(1);
|
||||
|
||||
calls = 0;
|
||||
realm.evaluateModule('import "test" with { animal: "monkey" }; import "test" with { animal: "elephant" };', 'case 8');
|
||||
expect(calls).toBe(2);
|
||||
|
||||
calls = 0;
|
||||
realm.evaluateModule('import "test"; import "test" with {};', 'case 9');
|
||||
expect(calls).toBe(1);
|
||||
});
|
||||
|
||||
test('Custom module records', () => {
|
||||
let evaluationPromise: PromiseObject;
|
||||
|
||||
class CustomModuleRecord extends AbstractModuleRecord {
|
||||
_pc(): PromiseCapabilityRecord {
|
||||
const it = NewPromiseCapability(this.Realm.Intrinsics['%Promise%']);
|
||||
const completion = skipDebugger(it) as NormalCompletion<PromiseCapabilityRecord>;
|
||||
if (completion.Type !== 'normal') {
|
||||
throw new Error('Expected normal completion');
|
||||
}
|
||||
return completion.Value;
|
||||
}
|
||||
|
||||
override LoadRequestedModules(): PromiseObject {
|
||||
const pc = this._pc();
|
||||
Call(pc.Resolve, Value.undefined, []);
|
||||
return pc.Promise;
|
||||
}
|
||||
|
||||
override Link() {}
|
||||
|
||||
override* Evaluate() {
|
||||
const pc = this._pc();
|
||||
yield* Call(pc.Reject, Value.undefined, [Value('error!')]);
|
||||
evaluationPromise = pc.Promise;
|
||||
return evaluationPromise;
|
||||
}
|
||||
|
||||
override GetExportedNames(): readonly JSStringValue[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
override ResolveExport(): never {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
const agent = new Agent({
|
||||
loadImportedModule(referrer, specifier, _attributes, _hostDefined, finish) {
|
||||
if (specifier !== 'dep') {
|
||||
throw new Error('Invalid specifier');
|
||||
}
|
||||
finish(new CustomModuleRecord({
|
||||
Realm: (referrer as AbstractModuleRecord).Realm,
|
||||
Environment: undefined,
|
||||
Namespace: undefined,
|
||||
HostDefined: {},
|
||||
}));
|
||||
},
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
|
||||
const calls: unknown[] = [];
|
||||
|
||||
const realm = new ManagedRealm({
|
||||
promiseRejectionTracker(promise, operation) {
|
||||
calls.push([promise, operation]);
|
||||
},
|
||||
});
|
||||
|
||||
realm.evaluateModule('import "dep"', 'entrypoint');
|
||||
|
||||
assert(calls.length >= 2); // there is a third call, for the promise of the entrypoint
|
||||
assert.deepStrictEqual(calls[0], [evaluationPromise!, 'reject'], "first call should be 'reject'");
|
||||
assert.deepStrictEqual(calls[1], [evaluationPromise!, 'handle'], "second call should be 'handle'");
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { createAgent, createRealm } from '../base.mts';
|
||||
import {
|
||||
CreateArrayFromList, CreateBuiltinFunction, CreateDataProperty, EnsureCompletion, FEATURES, NormalCompletion, setSurroundingAgent, skipDebugger, ToString, UndefinedValue, Value, type Arguments,
|
||||
} from '#self';
|
||||
|
||||
test('Every built-in function should have a section property', () => {
|
||||
const agent = createAgent({
|
||||
features: FEATURES.map((f) => f.name),
|
||||
});
|
||||
setSurroundingAgent(agent);
|
||||
const { realm } = createRealm();
|
||||
realm.scope(() => {
|
||||
skipDebugger(CreateDataProperty(
|
||||
realm.GlobalObject,
|
||||
Value('fail'),
|
||||
CreateBuiltinFunction(([path = Value.undefined]: Arguments) => {
|
||||
const o = EnsureCompletion(skipDebugger(ToString(path)));
|
||||
if (o.Type === 'throw') {
|
||||
return o;
|
||||
}
|
||||
throw new Error(`${o.Value.stringValue()} did not have a section`);
|
||||
}, 1, Value(''), []),
|
||||
));
|
||||
const targets: Value[] = [];
|
||||
Object.entries(realm.Intrinsics)
|
||||
.forEach(([k, v]) => {
|
||||
targets.push(CreateArrayFromList([Value(k), v]));
|
||||
});
|
||||
skipDebugger(CreateDataProperty(
|
||||
realm.GlobalObject,
|
||||
Value('targets'),
|
||||
CreateArrayFromList(targets),
|
||||
));
|
||||
});
|
||||
const result = realm.evaluateScript(`
|
||||
'use strict';
|
||||
|
||||
{
|
||||
const targets = globalThis.targets;
|
||||
delete globalThis.targets;
|
||||
const fail = globalThis.fail;
|
||||
delete globalThis.fail;
|
||||
|
||||
const topQueue = new Set();
|
||||
const scanned = new Set();
|
||||
const scan = (ns, path) => {
|
||||
if (scanned.has(ns)) {
|
||||
return;
|
||||
}
|
||||
scanned.add(ns);
|
||||
if (typeof ns === 'function') {
|
||||
if ($262.spec(ns) === undefined) {
|
||||
fail(path);
|
||||
}
|
||||
}
|
||||
if (typeof ns !== 'function' && (typeof ns !== 'object' || ns === null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const descriptors = Object.getOwnPropertyDescriptors(ns);
|
||||
Reflect.ownKeys(descriptors)
|
||||
.forEach((name) => {
|
||||
const desc = descriptors[name];
|
||||
const p = typeof name === 'symbol'
|
||||
? path + '[Symbol(' + name.description + ')]'
|
||||
: path + '.' + name;
|
||||
if ('value' in desc) {
|
||||
if (!topQueue.has(desc.value)) {
|
||||
scan(desc.value, p);
|
||||
}
|
||||
} else {
|
||||
if (!topQueue.has(desc.get)) {
|
||||
scan(desc.get, p);
|
||||
}
|
||||
if (!topQueue.has(desc.set)) {
|
||||
scan(desc.set, p);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
targets.forEach((t) => {
|
||||
topQueue.add(t[1]);
|
||||
});
|
||||
targets.forEach((t) => {
|
||||
scan(t[1], t[0]);
|
||||
});
|
||||
}
|
||||
`) as NormalCompletion<UndefinedValue>;
|
||||
expect(result).toBeInstanceOf(NormalCompletion);
|
||||
expect(result.Value).toBe(Value.undefined);
|
||||
});
|
||||
Reference in New Issue
Block a user