blob: a1ceaa02e71a0f3a8dd20575826e59d3b2ae40e0 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
// ES6 Function unit tests
WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
var tests = [
{
name: "change Symbol.hasInstance property of a normal function constructor",
body: function() {
var F = function (a, b) {
this.x = a;
this.y = b;
}
var checked = 0;
Object.defineProperty(F, Symbol.hasInstance, {
value: function () {
checked++;
return true;
}
});
assert.areEqual(true, undefined instanceof F, "undefined instanceof F");
assert.areEqual(1, checked, "Symbol.hasInstance in a normal function contructor - checked==1");
assert.areEqual(true, null instanceof F, "null instanceof F");
assert.areEqual(2, checked, "Symbol.hasInstance in a normal function contructor - checked==2");
assert.areEqual(true, true instanceof F, "true instanceof F");
assert.areEqual(3, checked, "Symbol.hasInstance in a normal function contructor - checked==3");
assert.areEqual(true, false instanceof F, "false instanceof F");
assert.areEqual(4, checked, "Symbol.hasInstance in a normal function contructor - checked==4");
assert.areEqual(true, 0 instanceof F, "0 instanceof F");
assert.areEqual(5, checked, "Symbol.hasInstance in a normal function contructor - checked==5");
assert.areEqual(true, 1.5e16 instanceof F, "1.5e16 instanceof F");
assert.areEqual(6, checked, "Symbol.hasInstance in a normal function contructor - checked==6");
assert.areEqual(true, NaN instanceof F, "NaN instanceof F");
assert.areEqual(7, checked, "Symbol.hasInstance in a normal function contructor - checked==7");
assert.areEqual(true, '' instanceof F, "'' instanceof F");
assert.areEqual(8, checked, "Symbol.hasInstance in a normal function contructor - checked==8");
assert.areEqual(true, 'abc' instanceof F, "'abc' instanceof F");
assert.areEqual(9, checked, "Symbol.hasInstance in a normal function contructor - checked==9");
assert.areEqual(true, {} instanceof F, "{} instanceof F");
assert.areEqual(10, checked, "Symbol.hasInstance in a normal function contructor - checked==10");
assert.areEqual(true, function(){} instanceof F, "function(){} instanceof F");
assert.areEqual(11, checked, "Symbol.hasInstance in a normal function contructor - checked==11");
}
},
{
name: "change Symbol.hasInstance property of a non-function objects",
body: function() {
[
{},
{0:1,"length":1},
[],
[0,1,2],
['abc'],
].forEach(function(item) {
testInstanceof(item);
});
function testInstanceof(O) {
var checked = 0;
var oldf = O[Symbol.hasInstance];
O[Symbol.hasInstance] = function() {
checked++;
return true;
};
assertInstanceOf(O);
O[Symbol.hasInstance] = oldf;
checked = 0;
var desc = Object.getOwnPropertyDescriptor(O, Symbol.hasInstance);
Object.defineProperty(O, Symbol.hasInstance, {
value: function () {
checked++;
return true;
}
});
assertInstanceOf(O);
Object.defineProperty(O, Symbol.hasInstance, desc);
function assertInstanceOf(O) {
assert.areEqual(true, undefined instanceof O, "undefined instanceof O");
assert.areEqual(1, checked, "Symbol.hasInstance in a non-function object - checked==1");
assert.areEqual(true, null instanceof O, "null instanceof O");
assert.areEqual(2, checked, "Symbol.hasInstance in a non-function object - checked==2");
assert.areEqual(true, true instanceof O, "true instanceof O");
assert.areEqual(3, checked, "Symbol.hasInstance in a non-function object - checked==3");
assert.areEqual(true, false instanceof O, "false instanceof O");
assert.areEqual(4, checked, "Symbol.hasInstance in a non-function object - checked==4");
assert.areEqual(true, 0 instanceof O, "0 instanceof O");
assert.areEqual(5, checked, "Symbol.hasInstance in a non-function object - checked==5");
assert.areEqual(true, 1.5e16 instanceof O, "1.5e16 instanceof O");
assert.areEqual(6, checked, "Symbol.hasInstance in a non-function object - checked==6");
assert.areEqual(true, NaN instanceof O, "NaN instanceof O");
assert.areEqual(7, checked, "Symbol.hasInstance in a non-function object - checked==7");
assert.areEqual(true, '' instanceof O, "'' instanceof O");
assert.areEqual(8, checked, "Symbol.hasInstance in a non-function object - checked==8");
assert.areEqual(true, 'abc' instanceof O, "'abc' instanceof O");
assert.areEqual(9, checked, "Symbol.hasInstance in a non-function object - checked==9");
assert.areEqual(true, {} instanceof O, "{} instanceof O");
assert.areEqual(10, checked, "Symbol.hasInstance in a non-function object - checked==10");
assert.areEqual(true, function(){} instanceof O, "function(){} instanceof O");
assert.areEqual(11, checked, "Symbol.hasInstance in a non-function object - checked==11");
}
}
}
},
{
name: "change Symbol.hasInstance property of a bound function constructor",
body: function() {
var F = function (a, b) {
this.x = a;
this.y = b;
}
var BoundF = F.bind(1,2);
var checked = 0;
Object.defineProperty(F, Symbol.hasInstance, {
value: function () {
checked++;
return true;
}
});
assert.areEqual(true, BoundF instanceof F, "BoundF instanceof F");
assert.areEqual(1, checked, "Symbol.hasInstance in a function contructor bound - checked==1");
assert.areEqual(true, Object.create(BoundF) instanceof F, "Object.create(BoundF) instanceof f");
assert.areEqual(2, checked, "Symbol.hasInstance in a function contructor bound - checked==2");
assert.areEqual(true, new BoundF() instanceof F, "new BoundF() instanceof F");
assert.areEqual(3, checked, "Symbol.hasInstance in a function contructor bound - checked==3");
assert.areEqual(true, Object.create(F.prototype) instanceof BoundF, "Object.create(F.prototype) instanceof F");
assert.areEqual(true, new F() instanceof BoundF, "instanceof f");
}
},
{
name: "change Symbol.hasInstance property of a proxy of function constructor",
body: function() {
function Foo() { };
var checked = 0;
var checkedString = [];
Object.defineProperty(Foo, Symbol.hasInstance, {
value: function () {
checked++;
return false;
}
});
var ProxyFoo = new Proxy(Foo, {
get : function (target, property){
checkedString.push(property.toString());
return Reflect.get(target, property);
}
});
assert.areEqual(false, new ProxyFoo() instanceof ProxyFoo, "new ProxyFoo() instanceof ProxyFoo");
assert.areEqual(1, checked, "Symbol.hasInstance in a function contructor through proxy - checked==1");
assert.areEqual(['Symbol(Symbol.hasInstance)'], checkedString, "checkedString==['Symbol(Symbol.hasInstance)']");
assert.areEqual(false, new ProxyFoo() instanceof Foo, "new ProxyFoo() instanceof Foo");
assert.areEqual(2, checked, "Symbol.hasInstance in a function contructor through proxy - checked==2");
}
},
{
name: "change Symbol.hasInstance property of a bound proxy of function constructor",
body: function() {
function Foo() { };
var checked = 0;
var checkedString = [];
Object.defineProperty(Foo, Symbol.hasInstance, {
value: function () {
checked++;
return false;
}
});
var ProxyFoo = new Proxy(Foo, {
get : function (target, property){
checkedString.push(property.toString());
return Reflect.get(target, property);
}
});
var BP = ProxyFoo.bind();
assert.areEqual(false, BP instanceof ProxyFoo, "BP instanceof ProxyFoo");
assert.areEqual(1, checked, "Symbol.hasInstance in a function contructor through bound proxy - checked==1");
assert.areEqual(['bind','length','name','Symbol(Symbol.hasInstance)'], checkedString, "checkedString value");
}
},
{
name: "instanceof operator and default instOfHandler gets 'prototype' property of right-hand side",
body: function() {
[
undefined,
null,
true,
false,
'string',
Symbol(),
0,
].forEach(function(item) {
testInstanceof(item, function(){});
});
function testInstanceof(prototypeObj, O) {
O.prototype = prototypeObj;
assert.throws(()=>{({}) instanceof O}, TypeError, "({}) instanceof O", "Function does not have a valid prototype object");
assert.throws(()=>{({0:1,"length":1}) instanceof O}, TypeError, "({0:1,\"length\":1}) instanceof O", "Function does not have a valid prototype object");
assert.throws(()=>{[] instanceof O}, TypeError, "[] instanceof O", "Function does not have a valid prototype object");
assert.throws(()=>{[0,1,2] instanceof O}, TypeError, "[0,1,2] instanceof O", "Function does not have a valid prototype object");
assert.throws(()=>{['abc'] instanceof O}, TypeError, "['abc'] instanceof O", "Function does not have a valid prototype object");
assert.throws(()=>{(function(){}) instanceof O}, TypeError, "(function(){}) instanceof O", "Function does not have a valid prototype object");
assert.throws(()=>{O[Symbol.hasInstance]({})}, TypeError, "O[Symbol.hasInstance]({})", "Function does not have a valid prototype object");
assert.throws(()=>{O[Symbol.hasInstance]({0:1,"length":1})}, TypeError, "O[Symbol.hasInstance]({0:1,\"length\":1})", "Function does not have a valid prototype object");
assert.throws(()=>{O[Symbol.hasInstance]([])}, TypeError, "O[Symbol.hasInstance]([])", "Function does not have a valid prototype object");
assert.throws(()=>{O[Symbol.hasInstance]([0,1,2])}, TypeError, "O[Symbol.hasInstance]([0,1,2])", "Function does not have a valid prototype object");
assert.throws(()=>{O[Symbol.hasInstance](['abc'])}, TypeError, "O[Symbol.hasInstance](['abc'])", "Function does not have a valid prototype object");
assert.throws(()=>{O[Symbol.hasInstance](function(){})}, TypeError, "O[Symbol.hasInstance](function(){})", "Function does not have a valid prototype object");
}
}
},
{
name: "instanceof operator calling user-defined instOfHandler converts the return value to boolean using ToBoolean abstract operation",
body: function() {
[
[function() { return undefined; }, false],
[function() { return null; }, false],
[function() { return NaN; }, false],
[function() { return 1; }, true],
[function() { return 0; }, false],
[function() { return ''; }, false],
[function() { return 'abc'; }, true],
[function() { return Symbol(); }, true],
[function() { return {}; }, true],
].forEach(function(item) {
testInstanceof(item[0], item[1], {});
testInstanceof(item[0], item[1], []);
});
function testInstanceof(instOfHandler, expected, O) {
O[Symbol.hasInstance] = instOfHandler;
assert.areEqual(expected, undefined instanceof O, "undefined instanceof O");
assert.areEqual(expected, null instanceof O, "null instanceof O");
assert.areEqual(expected, true instanceof O, "true instanceof O");
assert.areEqual(expected, false instanceof O, "false instanceof O");
assert.areEqual(expected, 0 instanceof O, "0 instanceof O");
assert.areEqual(expected, 1.5e16 instanceof O, "1.5e16 instanceof O");
assert.areEqual(expected, NaN instanceof O, "NaN instanceof O");
assert.areEqual(expected, '' instanceof O, "'' instanceof O");
assert.areEqual(expected, 'abc' instanceof O, "'abc' instanceof O");
assert.areEqual(expected, {} instanceof O, "{} instanceof O");
assert.areEqual(expected, function(){} instanceof O, "function(){} instanceof O");
}
}
},
{
name: "instanceof operator calling OrdinaryHasInstance abstract operation returns false on non-object left-hand side values",
body: function() {
var F = function() {};
[
undefined,
null,
true,
false,
'',
'abc',
Symbol(),
Symbol('abc'),
0,
1.5e16,
NaN,
].forEach(function(item) {
assert.isFalse(item instanceof F, typeof(item) == ('symbol' ? 'Symbol' : item) + " instanceof F");
});
}
},
{
name: "properties of Function.prototype[Symbol.hasInstance]",
body: function() {
var desc = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance);
assert.areEqual(false, desc.enumerable, "protype:enumerable==false");
assert.areEqual(false, desc.writable, "protype:writable==false");
assert.areEqual(false, desc.configurable, "protype:configurable==false");
var f = Function.prototype[Symbol.hasInstance];
assert.areEqual(1, f.length, "Function.prototype[Symbol.hasInstance].length==1");
desc = Object.getOwnPropertyDescriptor(f, 'length');
assert.areEqual(false, desc.enumerable, "length:enumerable==false");
assert.areEqual(false, desc.writable, "length:enumerable==false");
assert.areEqual(true, desc.configurable, "length:enumerable==true");
assert.areEqual('[Symbol.hasInstance]', f.name, "Function.prototype[Symbol.hasInstance].name");
desc = Object.getOwnPropertyDescriptor(f, 'name');
assert.areEqual(false, desc.enumerable, "name:enumerable==false");
assert.areEqual(false, desc.writable, "name:writable==false");
assert.areEqual(true, desc.configurable, "name:configurable==true");
assert.areEqual(false, f.call(), "Function.prototype[Symbol.hasInstance].call()");
assert.areEqual(false, f.call({}), "Function.prototype[Symbol.hasInstance].call({})");
}
},
{
name: "instanceof operator on callable object invokes get on 'prototype' property",
body: function() {
// method 'F' has no 'prototype' property
var F = Object.getOwnPropertyDescriptor({ get f() {} }, 'f').get;
Object.defineProperty(F, 'prototype', {
get: function() {
throw new Error('Hit prototype');
}
});
assert.throws(()=>{undefined instanceof F}, Error, "undefined instanceof F", 'Hit prototype');
}
},
{
name: "instanceof operator invokes [[getPrototypeOf]] internal method on left-hand side value",
body: function() {
var p = new Proxy({}, {
getPrototypeOf: function() {
throw new Error('Hit getPrototypeOf');
}
});
var obj = Object.create(p);
obj.prototype = {};
var F = function() {};
assert.throws(()=>{p instanceof F}, Error, "p instanceof F", 'Hit getPrototypeOf');
assert.throws(()=>{obj instanceof F}, Error, "obj instanceof F", 'Hit getPrototypeOf');
}
},
{
name: "changing Symbol.hasIstance property on a function contructor invalidates inline cache",
body: function() {
var F = function() {}
var changeHasInstance = function() {
Object.defineProperty(F, Symbol.hasInstance, {
value: function(inst) { return true; }
});
}
function func() {
return 0 instanceof F;
}
var changed = false;
for (var i=0; i<100; i++) {
var x = func();
assert.areEqual(changed, x, "i=="+i);
if (i==20) {
changeHasInstance();
changed = true;
}
}
}
},
{
name: "changing 'prototype' property on a function contructor invalidates inline cache",
body: function() {
var F = function() {}
var changeHasInstance = function() {
Object.defineProperty(F, 'prototype', {
value: Function.prototype
});
}
function func() {
return function(){} instanceof F;
}
var changed = false;
for (var i=0; i<100; i++) {
var x = func();
assert.areEqual(changed, x, "i=="+i);
if (i==20) {
changeHasInstance();
changed = true;
}
}
}
},
];
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });