281 lines
7.4 KiB
Go
281 lines
7.4 KiB
Go
|
package otto
|
||
|
|
||
|
import (
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func TestFunction(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
test(`
|
||
|
var abc = Object.getOwnPropertyDescriptor(Function, "prototype");
|
||
|
[ [ typeof Function.prototype, typeof Function.prototype.length, Function.prototype.length ],
|
||
|
[ abc.writable, abc.enumerable, abc.configurable ] ];
|
||
|
`, "function,number,0,false,false,false")
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func Test_argumentList2parameterList(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
is(argumentList2parameterList([]Value{toValue("abc, def"), toValue("ghi")}), []string{"abc", "def", "ghi"})
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestFunction_new(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
test(`raise:
|
||
|
new Function({});
|
||
|
`, "SyntaxError: Unexpected identifier")
|
||
|
|
||
|
test(`
|
||
|
var abc = Function("def, ghi", "jkl", "return def+ghi+jkl");
|
||
|
[ typeof abc, abc instanceof Function, abc("ab", "ba", 1) ];
|
||
|
`, "function,true,abba1")
|
||
|
|
||
|
test(`raise:
|
||
|
var abc = {
|
||
|
toString: function() { throw 1; }
|
||
|
};
|
||
|
var def = {
|
||
|
toString: function() { throw 2; }
|
||
|
};
|
||
|
var ghi = new Function(abc, def);
|
||
|
ghi;
|
||
|
`, "1")
|
||
|
|
||
|
// S15.3.2.1_A3_T10
|
||
|
test(`raise:
|
||
|
var abc = {
|
||
|
toString: function() { return "z;x"; }
|
||
|
};
|
||
|
var def = "return this";
|
||
|
var ghi = new Function(abc, def);
|
||
|
ghi;
|
||
|
`, "SyntaxError: Unexpected token ;")
|
||
|
|
||
|
test(`raise:
|
||
|
var abc;
|
||
|
var def = "return true";
|
||
|
var ghi = new Function(null, def);
|
||
|
ghi;
|
||
|
`, "SyntaxError: Unexpected token null")
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestFunction_apply(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
test(`Function.prototype.apply.length`, 2)
|
||
|
test(`String.prototype.substring.apply("abc", [1, 11])`, "bc")
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestFunction_call(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
test(`Function.prototype.call.length`, 1)
|
||
|
test(`String.prototype.substring.call("abc", 1, 11)`, "bc")
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestFunctionArguments(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
// Should not be able to delete arguments
|
||
|
test(`
|
||
|
function abc(def, arguments){
|
||
|
delete def;
|
||
|
return def;
|
||
|
}
|
||
|
abc(1);
|
||
|
`, 1)
|
||
|
|
||
|
// Again, should not be able to delete arguments
|
||
|
test(`
|
||
|
function abc(def){
|
||
|
delete def;
|
||
|
return def;
|
||
|
}
|
||
|
abc(1);
|
||
|
`, 1)
|
||
|
|
||
|
// Test typeof of a function argument
|
||
|
test(`
|
||
|
function abc(def, ghi, jkl){
|
||
|
return typeof jkl
|
||
|
}
|
||
|
abc("1st", "2nd", "3rd", "4th", "5th");
|
||
|
`, "string")
|
||
|
|
||
|
test(`
|
||
|
function abc(def, ghi, jkl){
|
||
|
arguments[0] = 3.14;
|
||
|
arguments[1] = 'Nothing happens';
|
||
|
arguments[2] = 42;
|
||
|
if (3.14 === def && 'Nothing happens' === ghi && 42 === jkl)
|
||
|
return true;
|
||
|
}
|
||
|
abc(-1, 4.2, 314);
|
||
|
`, true)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestFunctionDeclarationInFunction(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
// Function declarations happen AFTER parameter/argument declarations
|
||
|
// That is, a function declared within a function will shadow/overwrite
|
||
|
// declared parameters
|
||
|
|
||
|
test(`
|
||
|
function abc(def){
|
||
|
return def;
|
||
|
function def(){
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
typeof abc();
|
||
|
`, "function")
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestArguments_defineOwnProperty(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
test(`
|
||
|
var abc;
|
||
|
var def = true;
|
||
|
var ghi = {};
|
||
|
(function (a, b, c) {
|
||
|
Object.defineProperty(arguments, "0", {
|
||
|
value: 42,
|
||
|
writable: false,
|
||
|
enumerable: false,
|
||
|
configurable: false
|
||
|
});
|
||
|
Object.defineProperty(arguments, "1", {
|
||
|
value: 3.14,
|
||
|
configurable: true,
|
||
|
enumerable: true
|
||
|
});
|
||
|
abc = Object.getOwnPropertyDescriptor(arguments, "0");
|
||
|
for (var name in arguments) {
|
||
|
ghi[name] = (ghi[name] || 0) + 1;
|
||
|
if (name === "0") {
|
||
|
def = false;
|
||
|
}
|
||
|
}
|
||
|
}(0, 1, 2));
|
||
|
[ abc.value, abc.writable, abc.enumerable, abc.configurable, def, ghi["1"] ];
|
||
|
`, "42,false,false,false,true,1")
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestFunction_bind(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
defer mockUTC()()
|
||
|
|
||
|
test(`
|
||
|
abc = function(){
|
||
|
return "abc";
|
||
|
};
|
||
|
def = abc.bind();
|
||
|
[ typeof def.prototype, typeof def.hasOwnProperty, def.hasOwnProperty("caller"), def.hasOwnProperty("arguments"), def() ];
|
||
|
`, "object,function,true,true,abc")
|
||
|
|
||
|
test(`
|
||
|
abc = function(){
|
||
|
return arguments[1];
|
||
|
};
|
||
|
def = abc.bind(undefined, "abc");
|
||
|
ghi = abc.bind(undefined, "abc", "ghi");
|
||
|
[ def(), def("def"), ghi("def") ];
|
||
|
`, ",def,ghi")
|
||
|
|
||
|
test(`
|
||
|
var abc = function () {};
|
||
|
var ghi;
|
||
|
try {
|
||
|
Object.defineProperty(Function.prototype, "xyzzy", {
|
||
|
value: 1001,
|
||
|
writable: true,
|
||
|
enumerable: true,
|
||
|
configurable: true
|
||
|
});
|
||
|
var def = abc.bind({});
|
||
|
ghi = !def.hasOwnProperty("xyzzy") && ghi.xyzzy === 1001;
|
||
|
} finally {
|
||
|
delete Function.prototype.xyzzy;
|
||
|
}
|
||
|
[ ghi ];
|
||
|
`, "true")
|
||
|
|
||
|
test(`
|
||
|
var abc = function (def, ghi) {};
|
||
|
var jkl = abc.bind({});
|
||
|
var mno = abc.bind({}, 1, 2);
|
||
|
[ jkl.length, mno.length ];
|
||
|
`, "2,0")
|
||
|
|
||
|
test(`raise:
|
||
|
Math.bind();
|
||
|
`, "TypeError: 'bind' is not a function")
|
||
|
|
||
|
test(`
|
||
|
function construct(fn, arguments) {
|
||
|
var bound = Function.prototype.bind.apply(fn, [null].concat(arguments));
|
||
|
return new bound();
|
||
|
}
|
||
|
var abc = construct(Date, [1957, 4, 27]);
|
||
|
Object.prototype.toString.call(abc);
|
||
|
`, "[object Date]")
|
||
|
|
||
|
test(`
|
||
|
var fn = function (x, y, z) {
|
||
|
var result = {};
|
||
|
result.abc = x + y + z;
|
||
|
result.def = arguments[0] === "a" && arguments.length === 3;
|
||
|
return result;
|
||
|
};
|
||
|
var newFn = Function.prototype.bind.call(fn, {}, "a", "b", "c");
|
||
|
var result = new newFn();
|
||
|
[ result.hasOwnProperty("abc"), result.hasOwnProperty("def"), result.abc, result.def ];
|
||
|
`, "true,true,abc,true")
|
||
|
|
||
|
test(`
|
||
|
abc = function(){
|
||
|
return "abc";
|
||
|
};
|
||
|
def = abc.bind();
|
||
|
def.toString();
|
||
|
`, "function () { [native code] }")
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestFunction_toString(t *testing.T) {
|
||
|
tt(t, func() {
|
||
|
test, _ := test()
|
||
|
|
||
|
test(`raise:
|
||
|
Function.prototype.toString.call(undefined);
|
||
|
`, "TypeError")
|
||
|
|
||
|
test(`
|
||
|
abc = function() { return -1 ;
|
||
|
}
|
||
|
1;
|
||
|
abc.toString();
|
||
|
`, "function() { return -1 ;\n}")
|
||
|
})
|
||
|
}
|