Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions test/parallel/test-vm-global-property-enumerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const assert = require('assert');

const cases = [
{
get 1() {
return 'value';
},
get key() {
return 'value';
},
Expand All @@ -15,28 +18,39 @@ const cases = [
// Intentionally single setter.
// eslint-disable-next-line accessor-pairs
set key(value) {},
// eslint-disable-next-line accessor-pairs
set 1(value) {},
},
{},
{
key: 'value',
1: 'value',
},
(new class GetterObject {
get key() {
return 'value';
}
get 1() {
return 'value';
}
}()),
(new class SetterObject {
// Intentionally single setter.
// eslint-disable-next-line accessor-pairs
set key(value) {
// noop
}
// eslint-disable-next-line accessor-pairs
set 1(value) {
// noop
}
}()),
[],
[['key', 'value']],
{
__proto__: {
key: 'value',
1: 'value',
},
},
];
Expand Down
224 changes: 193 additions & 31 deletions test/parallel/test-vm-global-property-prototype.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,160 @@ require('../common');
const assert = require('assert');
const vm = require('vm');

const outerProto = {
onOuterProto: 'onOuterProto',
bothProto: 'onOuterProto',
};
function onOuterProtoGetter() {
return 'onOuterProtoGetter';
}
Object.defineProperties(outerProto, {
onOuterProtoGetter: {
get: onOuterProtoGetter,
},
bothProtoGetter: {
get: onOuterProtoGetter,
},
// outer proto indexed
0: {
value: 'onOuterProtoIndexed',
writable: false,
enumerable: false,
configurable: true,
},
// both proto indexed
3: {
value: 'onOuterProtoIndexed',
writable: false,
enumerable: false,
configurable: true,
},
});

// Creating a new intermediate proto to mimic the
// window -> Window.prototype -> EventTarget.prototype chain in JSDom.
const sandboxProto = {
__proto__: outerProto,
};

const sandbox = {
__proto__: sandboxProto,
onSelf: 'onSelf',
};

function onSelfGetter() {
return 'onSelfGetter';
}

Object.defineProperty(sandbox, 'onSelfGetter', {
get: onSelfGetter,
});

Object.defineProperty(sandbox, 1, {
value: 'onSelfIndexed',
writable: false,
enumerable: false,
configurable: true,
Object.defineProperties(sandbox, {
onSelfGetter: {
get: onSelfGetter,
},
1: {
value: 'onSelfIndexed',
writable: false,
enumerable: false,
configurable: true,
}
});

const ctx = vm.createContext(sandbox);

const result = vm.runInContext(`
Object.prototype.onProto = 'onProto';
Object.defineProperty(Object.prototype, 'onProtoGetter', {
get() {
return 'onProtoGetter';
Object.prototype.onInnerProto = 'onInnerProto';
Object.defineProperties(Object.prototype, {
onInnerProtoGetter: {
get() {
return 'onInnerProtoGetter';
},
},
2: {
value: 'onInnerProtoIndexed',
writable: false,
enumerable: false,
configurable: true,
},
});
Object.defineProperty(Object.prototype, 2, {
value: 'onProtoIndexed',
writable: false,
enumerable: false,
configurable: true,

// Override outer proto properties
Object.prototype.bothProto = 'onInnerProto';
Object.defineProperties(Object.prototype, {
bothProtoGetter: {
get() {
return 'onInnerProtoGetter';
},
},
// outer proto indexed
3: {
value: 'onInnerProtoIndexed',
writable: false,
enumerable: false,
configurable: true,
},
});

const resultHasOwn = {
onSelf: Object.hasOwn(this, 'onSelf'),
onSelfGetter: Object.hasOwn(this, 'onSelfGetter'),
onSelfIndexed: Object.hasOwn(this, 1),
onProto: Object.hasOwn(this, 'onProto'),
onProtoGetter: Object.hasOwn(this, 'onProtoGetter'),
onProtoIndexed: Object.hasOwn(this, 2),
onOuterProto: Object.hasOwn(this, 'onOuterProto'),
onOuterProtoGetter: Object.hasOwn(this, 'onOuterProtoGetter'),
onOuterProtoIndexed: Object.hasOwn(this, 0),
onInnerProto: Object.hasOwn(this, 'onInnerProto'),
onInnerProtoGetter: Object.hasOwn(this, 'onInnerProtoGetter'),
onInnerProtoIndexed: Object.hasOwn(this, 2),
bothProto: Object.hasOwn(this, 'bothProto'),
bothProtoGetter: Object.hasOwn(this, 'bothProtoGetter'),
bothProtoIndexed: Object.hasOwn(this, 3),
};

const getDesc = (prop) => Object.getOwnPropertyDescriptor(this, prop);
const resultDesc = {
onSelf: getDesc('onSelf'),
onSelfGetter: getDesc('onSelfGetter'),
onSelfIndexed: getDesc(1),
onProto: getDesc('onProto'),
onProtoGetter: getDesc('onProtoGetter'),
onProtoIndexed: getDesc(2),
onOuterProto: getDesc('onOuterProto'),
onOuterProtoGetter: getDesc('onOuterProtoGetter'),
onOuterProtoIndexed: getDesc(0),
onInnerProto: getDesc('onInnerProto'),
onInnerProtoGetter: getDesc('onInnerProtoGetter'),
onInnerProtoIndexed: getDesc(2),
bothProto: getDesc('bothProto'),
bothProtoGetter: getDesc('bothProtoGetter'),
bothProtoIndexed: getDesc(3),
};
const resultIn = {
onSelf: 'onSelf' in this,
onSelfGetter: 'onSelfGetter' in this,
onSelfIndexed: 1 in this,
onOuterProto: 'onOuterProto' in this,
onOuterProtoGetter: 'onOuterProtoGetter' in this,
onOuterProtoIndexed: 0 in this,
onInnerProto: 'onInnerProto' in this,
onInnerProtoGetter: 'onInnerProtoGetter' in this,
onInnerProtoIndexed: 2 in this,
bothProto: 'bothProto' in this,
bothProtoGetter: 'bothProtoGetter' in this,
bothProtoIndexed: 3 in this,
};
const resultValue = {
onSelf: this.onSelf,
onSelfGetter: this.onSelfGetter,
onSelfIndexed: this[1],
onOuterProto: this.onOuterProto,
onOuterProtoGetter: this.onOuterProtoGetter,
onOuterProtoIndexed: this[0],
onInnerProto: this.onInnerProto,
onInnerProtoGetter: this.onInnerProtoGetter,
onInnerProtoIndexed: this[2],
bothProto: this.bothProto,
bothProtoGetter: this.bothProtoGetter,
bothProtoIndexed: this[3],
};
({
resultHasOwn,
resultDesc,
resultIn,
resultValue,
});
`, ctx);

Expand All @@ -68,16 +166,80 @@ assert.deepEqual(result, {
onSelf: true,
onSelfGetter: true,
onSelfIndexed: true,
onProto: false,
onProtoGetter: false,
onProtoIndexed: false,

// All prototype properties are not own properties.
onOuterProto: false,
onOuterProtoGetter: false,
onOuterProtoIndexed: false,
onInnerProto: false,
onInnerProtoGetter: false,
onInnerProtoIndexed: false,
bothProto: false,
bothProtoGetter: false,
bothProtoIndexed: false,
},
resultDesc: {
onSelf: { value: 'onSelf', writable: true, enumerable: true, configurable: true },
onSelfGetter: { get: onSelfGetter, set: undefined, enumerable: false, configurable: false },
onSelfIndexed: { value: 'onSelfIndexed', writable: false, enumerable: false, configurable: true },
onProto: undefined,
onProtoGetter: undefined,
onProtoIndexed: undefined,

// All prototype properties are not own properties.
onOuterProto: undefined,
onOuterProtoGetter: undefined,
onOuterProtoIndexed: undefined,
onInnerProto: undefined,
onInnerProtoGetter: undefined,
onInnerProtoIndexed: undefined,
bothProto: undefined,
bothProtoGetter: undefined,
bothProtoIndexed: undefined,
},
resultIn: {
onSelf: true,
onSelfGetter: true,
onSelfIndexed: true,

// Only properties exist on inner prototype chain will be looked up
// on `in` operator. In the VM Context, the prototype chain will be like:
// ```
// Object
// ^
// | prototype
// InnerPrototype
// ^
// | prototype
// globalThis
// ```
// Outer prototype is not in the inner global object prototype chain and it
// will not be looked up on `in` operator.
onOuterProto: false,
onOuterProtoGetter: false,
onOuterProtoIndexed: false,
onInnerProto: true,
onInnerProtoGetter: true,
onInnerProtoIndexed: true,
bothProto: true,
bothProtoGetter: true,
bothProtoIndexed: true,
},
resultValue: {
onSelf: 'onSelf',
onSelfGetter: 'onSelfGetter',
onSelfIndexed: 'onSelfIndexed',

// FIXME(legendecas): The outer prototype is not observable from the inner
// vm. Allowing property getter on the outer prototype can be confusing
// comparing to the normal JavaScript objects.
// Additionally, this may expose unexpected properties on the outer
// prototype chain, like polyfills, to the vm context.
onOuterProto: 'onOuterProto',
onOuterProtoGetter: 'onOuterProtoGetter',
onOuterProtoIndexed: 'onOuterProtoIndexed',
onInnerProto: 'onInnerProto',
onInnerProtoGetter: 'onInnerProtoGetter',
onInnerProtoIndexed: 'onInnerProtoIndexed',
bothProto: 'onOuterProto',
bothProtoGetter: 'onOuterProtoGetter',
bothProtoIndexed: 'onOuterProtoIndexed',
},
});