tests: Realm.prototype.evaluate semantics

This commit is contained in:
rwaldron 2021-07-16 12:01:09 -04:00 committed by Rick Waldron
parent 935d08814e
commit b2f34c0894
14 changed files with 479 additions and 0 deletions

View File

@ -0,0 +1,25 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate coerces the argument to a string.
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
assert.sameValue(r.evaluate(['1+1']), 2);
assert.sameValue(r.evaluate({ [Symbol.toPrimitive]() { return '1+1'; }}), 2);
assert.sameValue(r.evaluate(1), 1);
assert.sameValue(r.evaluate(null), null);
assert.sameValue(r.evaluate(undefined), undefined);
assert.sameValue(r.evaluate(true), true);
assert.sameValue(r.evaluate(false), false);

View File

@ -0,0 +1,22 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wraps errors from other realm into TypeErrors
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
assert.throws(TypeError, () => r.evaluate('...'), 'SyntaxError => TypeError');
assert.throws(TypeError, () => r.evaluate('throw 42'), 'throw primitive => TypeError');
assert.throws(TypeError, () => r.evaluate('throw new ReferenceError("aaa")'), 'custom ctor => TypeError');
assert.throws(TypeError, () => r.evaluate('throw new TypeError("aaa")'), 'Child TypeError => Parent TypeError');

View File

@ -0,0 +1,28 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate returns primitive values
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
assert.sameValue(r.evaluate('1 + 1'), 2);
assert.sameValue(r.evaluate('null'), null);
assert.sameValue(r.evaluate(''), undefined, 'undefined from empty completion');
assert.sameValue(r.evaluate('undefined'), undefined);
assert.sameValue(r.evaluate('true'), true);
assert.sameValue(r.evaluate('false'), false);
assert.sameValue(r.evaluate('function fn() {}'), undefined, 'fn declaration has empty completion');
assert.sameValue(r.evaluate('-0'), -0);
assert.sameValue(r.evaluate('"str"'), 'str');
assert(Number.isNaN(r.evaluate('NaN')));

View File

@ -0,0 +1,24 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate returns symbol values
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
const s = r.evaluate('Symbol()');
assert.sameValue(typeof s, 'symbol');
assert.sameValue(s.constructor, Symbol, 'primitive does not expose other Realm constructor');
assert.sameValue(Object.getPrototypeOf(s), Symbol.prototype);
assert.sameValue(r.evaluate('Symbol.for("x")'), Symbol.for('x'));
assert.sameValue(Symbol.prototype.toString.call(s), 'Symbol()');

View File

@ -0,0 +1,28 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate throws a TypeError if evaluate resolves to non-primitive values
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
assert.throws(TypeError, () => r.evaluate('globalThis'), 'globalThis');
assert.throws(TypeError, () => r.evaluate('[]'), 'array literal');
assert.throws(TypeError, () => r.evaluate(`
({
[Symbol.toPrimitive]() { return 'string'; },
toString() { return 'str'; },
valueOf() { return 1; }
});
`), 'object literal with immediate primitive coercion methods');
assert.throws(TypeError, () => r.evaluate('Object.create(null)'), 'ordinary object with null __proto__');

View File

@ -0,0 +1,47 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wrapped function arguments are wrapped into the inner realm, extended.
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
const blueFn = (x, y) => x + y;
const redWrappedFn = r.evaluate(`
function fn(wrapped1, wrapped2, wrapped3) {
if (wrapped1.x) {
return 1;
}
if (wrapped2.x) {
return 2;
}
if (wrapped3.x) {
// Not unwrapped
return 3;
}
if (wrapped1 === wrapped2) {
// Always a new wrapped function
return 4;
}
// No unwrapping
if (wrapped3 === fn) {
return 5;
};
return true;
}
fn.x = 'secret';
fn;
`);
assert.sameValue(redWrappedFn(blueFn, blueFn, redWrappedFn), true);

View File

@ -0,0 +1,25 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wrapped function arguments are wrapped into the inner realm
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
const blueFn = (x, y) => x + y;
const redWrappedFn = r.evaluate(`
0, function(blueWrappedFn, a, b, c) {
return blueWrappedFn(a, b) * c;
}
`);
assert.sameValue(redWrappedFn(blueFn, 2, 3, 4), 20);

View File

@ -0,0 +1,68 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wrapped function from return values share no identity.
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
r.evaluate(`
function fn() { return 42; }
globalThis.arrow = x => x * 2;
globalThis.pFn = new Proxy(fn, {
apply() {
pFn.used = 1;
return 39;
}
});
async function aFn() {
return 1;
}
function * genFn() {
return 1;
}
fn.x = 'secrets';
arrow.x = 'secrets';
pFn.x = 'secrets';
aFn.x = 'secrets';
genFn.x = 'secrets';
`)
const wrappedOrdinary = r.evaluate('() => fn')();
assert.sameValue(typeof wrappedOrdinary, 'function', 'ordinary function wrapped');
assert.sameValue(wrappedOrdinary(), 42, 'ordinary, return');
assert.sameValue(wrappedOrdinary.x, undefined, 'ordinary, no property shared');
const wrappedArrow = r.evaluate('() => arrow')();
assert.sameValue(typeof wrappedArrow, 'function', 'arrow function wrapped');
assert.sameValue(wrappedArrow(7), 14, 'arrow function, return');
assert.sameValue(wrappedArrow.x, undefined, 'arrow function, no property');
const wrappedProxied = r.evaluate('() => pFn')();
assert.sameValue(typeof wrappedProxied, 'function', 'proxied ordinary function wrapped');
assert.sameValue(r.evaluate('pFn.used'), undefined, 'pFn not called yet');
assert.sameValue(wrappedProxied(), 39, 'return of the proxied callable');
assert.sameValue(r.evaluate('pFn.used'), 1, 'pfn called');
assert.sameValue(wrappedProxied.x, undefined, 'proxy callable, no property');
const wrappedAsync = r.evaluate('() => aFn')();
assert.sameValue(typeof wrappedAsync, 'function', 'async function wrapped');
assert.throws(TypeError, () => wrappedAsync(), 'wrapped function cannot return non callable object');
assert.sameValue(wrappedAsync.x, undefined, 'async fn, no property');
const wrappedGenerator = r.evaluate('() => genFn')();
assert.sameValue(typeof wrappedGenerator, 'function', 'gen function wrapped');
assert.throws(TypeError, () => wrappedGenerator(), 'wrapped function cannot return non callable object');
assert.sameValue(wrappedGenerator.x, undefined, 'generator, no property');

View File

@ -0,0 +1,35 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wrapped function observing their scopes
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
let myValue;
function blueFn(x) {
myValue = x;
return myValue;
}
// cb is a new function in the red Realm that chains the call to the blueFn
const redFunction = r.evaluate(`
var myValue = 'red';
0, function(cb) {
cb(42);
return myValue;
};
`);
assert.sameValue(redFunction(blueFn), 'red');
assert.sameValue(myValue, 42);

View File

@ -0,0 +1,24 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate accepts callable objects
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
assert.sameValue(typeof r.evaluate('function fn() {} fn'), 'function', 'value from a fn declaration');
assert.sameValue(typeof r.evaluate('(function() {})'), 'function', 'function expression');
assert.sameValue(typeof r.evaluate('(async function() {})'), 'function', 'async function expression');
assert.sameValue(typeof r.evaluate('(function*() {})'), 'function', 'generator expression');
assert.sameValue(typeof r.evaluate('(async function*() {})'), 'function', 'async generator expression');
assert.sameValue(typeof r.evaluate('() => {}'), 'function', 'arrow function');

View File

@ -0,0 +1,26 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wrapped functions can resolve callable returns.
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
const wrapped = r.evaluate('x => y => x * y');
const nestedWrapped = wrapped(2);
const otherNestedWrapped = wrapped(4);
assert.sameValue(otherNestedWrapped(3), 12);
assert.sameValue(nestedWrapped(3), 6);
assert.notSameValue(nestedWrapped, otherNestedWrapped, 'new wrapping for each return');

View File

@ -0,0 +1,30 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wrapped functions produce new wrapping on each evaluation.
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
r.evaluate(`
function fn() {
return 42;
}
`);
const wrapped = r.evaluate('fn');
const otherWrapped = r.evaluate('fn');
assert.notSameValue(wrapped, otherWrapped);
assert.sameValue(typeof wrapped, 'function');
assert.sameValue(typeof otherWrapped, 'function');

View File

@ -0,0 +1,68 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wrapped functions share no properties, extended
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
r.evaluate(`
function fn() { return 42; }
globalThis.arrow = x => x * 2;
globalThis.pFn = new Proxy(fn, {
apply() {
pFn.used = 1;
return 39;
}
});
async function aFn() {
return 1;
}
function * genFn() {
return 1;
}
fn.x = 'secrets';
arrow.x = 'secrets';
pFn.x = 'secrets';
aFn.x = 'secrets';
genFn.x = 'secrets';
`);
const wrappedOrdinary = r.evaluate('fn');
assert.sameValue(typeof wrappedOrdinary, 'function', 'ordinary function wrapped');
assert.sameValue(wrappedOrdinary(), 42, 'ordinary, return');
assert.sameValue(wrappedOrdinary.x, undefined, 'ordinary, no property shared');
const wrappedArrow = r.evaluate('arrow');
assert.sameValue(typeof wrappedArrow, 'function', 'arrow function wrapped');
assert.sameValue(wrappedArrow(7), 14, 'arrow function, return');
assert.sameValue(wrappedArrow.x, undefined, 'arrow function, no property');
const wrappedProxied = r.evaluate('pFn');
assert.sameValue(typeof wrappedProxied, 'function', 'proxied ordinary function wrapped');
assert.sameValue(r.evaluate('pFn.used'), undefined, 'pFn not called yet');
assert.sameValue(wrappedProxied(), 39, 'return of the proxied callable');
assert.sameValue(r.evaluate('pFn.used'), 1, 'pfn called');
assert.sameValue(wrappedProxied.x, undefined, 'proxy callable, no property');
const wrappedAsync = r.evaluate('aFn');
assert.sameValue(typeof wrappedAsync, 'function', 'async function wrapped');
assert.throws(TypeError, () => wrappedAsync(), 'wrapped function cannot return non callable object');
assert.sameValue(wrappedAsync.x, undefined, 'async fn, no property');
const wrappedGenerator = r.evaluate('genFn');
assert.sameValue(typeof wrappedGenerator, 'function', 'gen function wrapped');
assert.throws(TypeError, () => wrappedGenerator(), 'wrapped function cannot return non callable object');
assert.sameValue(wrappedGenerator.x, undefined, 'generator, no property');

View File

@ -0,0 +1,29 @@
// Copyright (C) 2021 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-realm.prototype.evaluate
description: >
Realm.prototype.evaluate wrapped functions share no properties
includes: [isConstructor.js]
features: [callable-boundary-realms]
---*/
assert.sameValue(
typeof Realm.prototype.evaluate,
'function',
'This test must fail if Realm.prototype.evaluate is not a function'
);
const r = new Realm();
const wrapped = r.evaluate(`
function fn() {
return fn.secret;
}
fn.secret = 'confidential';
fn;
`);
assert.sameValue(wrapped.secret, undefined);
assert.sameValue(wrapped(), 'confidential');