mirror of
https://github.com/robertkrimen/otto
synced 2025-10-19 19:55:30 +08:00
425 lines
7.5 KiB
Go
425 lines
7.5 KiB
Go
package otto
|
|
|
|
import (
|
|
. "./terst"
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
"unicode/utf16"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
var (
|
|
_runTestWithOtto = struct {
|
|
Otto *Otto
|
|
test func(string, ...interface{}) Value
|
|
}{}
|
|
)
|
|
|
|
func failSet(name string, value interface{}) {
|
|
err := _runTestWithOtto.Otto.Set(name, value)
|
|
Is(err, nil)
|
|
if err != nil {
|
|
Terst().TestingT.FailNow()
|
|
}
|
|
}
|
|
|
|
func runTestWithOtto() (*Otto, func(string, ...interface{}) Value) {
|
|
cache := &_runTestWithOtto
|
|
Otto := New()
|
|
test := func(name string, expect ...interface{}) Value {
|
|
raise := false
|
|
defer func() {
|
|
if caught := recover(); caught != nil {
|
|
if raise {
|
|
if len(expect) > 0 {
|
|
Is(caught, expect[0])
|
|
}
|
|
} else {
|
|
dbg("Panic, caught:", caught)
|
|
panic(caught)
|
|
}
|
|
}
|
|
}()
|
|
var value Value
|
|
if isIdentifier(name) {
|
|
value = Otto.getValue(name)
|
|
} else {
|
|
source := name
|
|
index := strings.Index(source, "raise:")
|
|
if index == 0 {
|
|
raise = true
|
|
source = source[6:]
|
|
source = strings.TrimLeft(source, " ")
|
|
}
|
|
value = Otto.run(source)
|
|
}
|
|
value = Otto.runtime.GetValue(value)
|
|
if len(expect) > 0 {
|
|
Is(value, expect[0])
|
|
}
|
|
return value
|
|
}
|
|
cache.Otto = Otto
|
|
cache.test = test
|
|
return Otto, test
|
|
}
|
|
|
|
func runTest() func(string, ...interface{}) Value {
|
|
_, test := runTestWithOtto()
|
|
return test
|
|
}
|
|
|
|
func TestTransformRegExp(t *testing.T) {
|
|
Terst(t)
|
|
|
|
Is(transformRegExp(`\\|'|\r|\n|\t|\u2028|\u2029`), `\\|'|\r|\n|\t|\x{2028}|\x{2029}`)
|
|
Is(transformRegExp(`\x`), `x`)
|
|
Is(transformRegExp(`\u0z01\x\undefined`), `u0z01xundefined`)
|
|
}
|
|
|
|
func TestIsValidRegExp(t *testing.T) {
|
|
Terst(t)
|
|
|
|
IsTrue(isValidRegExp(""))
|
|
IsTrue(isValidRegExp("[0-9]"))
|
|
IsTrue(isValidRegExp("[(?=(?!]"))
|
|
IsTrue(isValidRegExp("\\(?="))
|
|
IsTrue(isValidRegExp("(\\?!"))
|
|
IsTrue(isValidRegExp("(?\\="))
|
|
IsFalse(isValidRegExp("(?="))
|
|
IsFalse(isValidRegExp("\\((?!"))
|
|
IsFalse(isValidRegExp("[0-9](?!"))
|
|
}
|
|
|
|
func TestOtto(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
test("xyzzy = 2", "2")
|
|
test("xyzzy + 2", "4")
|
|
test("xyzzy += 16", "18")
|
|
test("xyzzy", "18")
|
|
test(`
|
|
(function(){
|
|
return 1
|
|
})()
|
|
`, "1")
|
|
test(`
|
|
(function(){
|
|
return 1
|
|
}).call(this)
|
|
`, "1")
|
|
test(`
|
|
(function(){
|
|
var result
|
|
(function(){
|
|
result = -1
|
|
})()
|
|
return result
|
|
})()
|
|
`, "-1")
|
|
test(`
|
|
var abc = 1
|
|
abc || (abc = -1)
|
|
abc
|
|
`, "1")
|
|
test(`
|
|
var abc = (function(){ 1 === 1 })();
|
|
abc;
|
|
`, "undefined")
|
|
}
|
|
|
|
func TestSpeed(t *testing.T) {
|
|
Terst(t)
|
|
|
|
return
|
|
test := underscoreTest()
|
|
test(`
|
|
size = 300000
|
|
if (false) {
|
|
array = new Array(size)
|
|
for (i = 0; i < array.length; i++) {
|
|
array[i] = i
|
|
}
|
|
}
|
|
else if (true) {
|
|
Math.max.apply(Math, _.range(1, size))
|
|
}
|
|
else if (true) {
|
|
_.max(_.range(1,size))
|
|
}
|
|
else {
|
|
_.range(1,size)
|
|
}
|
|
`)
|
|
}
|
|
|
|
func Test_typeof(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
test(`typeof abc`, "undefined")
|
|
test(`typeof abc === 'undefined'`, "true")
|
|
test(`typeof {}`, "object")
|
|
test(`typeof null`, "object")
|
|
}
|
|
|
|
func Test_PrimitiveValueObjectValue(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
Number11 := test(`new Number(11)`)
|
|
Is(toFloat(Number11), "11")
|
|
}
|
|
|
|
func Test_eval(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
|
|
test(`
|
|
abc = 1
|
|
`)
|
|
|
|
test(`
|
|
eval("abc += 1")
|
|
`, "2")
|
|
|
|
test(`
|
|
(function(){
|
|
var abc = 11
|
|
eval("abc += 1")
|
|
return abc
|
|
})()
|
|
`, "12")
|
|
test(`abc`, "2")
|
|
|
|
test(`
|
|
var ghi;
|
|
(function(){
|
|
try {
|
|
eval("var prop = \\u2029;");
|
|
return false;
|
|
} catch (abc) {
|
|
ghi = abc.toString()
|
|
return abc instanceof SyntaxError;
|
|
}
|
|
})()
|
|
`, "true")
|
|
// TODO Make this a sane result
|
|
// Lightning bolt, lightning bolt, lightning bolt, ...
|
|
test(`ghi`, "SyntaxError: Unexpected token ILLEGAL ()")
|
|
|
|
test(`
|
|
function abc(){
|
|
this.THIS = eval("this");
|
|
}
|
|
var def = new abc();
|
|
def === def.THIS;
|
|
`, "true")
|
|
}
|
|
|
|
func Test_evalDirectIndirect(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
test(`
|
|
var abc = "global";
|
|
(function(){
|
|
try {
|
|
var _eval = eval;
|
|
var abc = "function";
|
|
if (
|
|
_eval("\'global\' === abc") === true && // eval (Indirect)
|
|
eval("\'function\' === abc") === true // eval (Direct)
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
} finally {
|
|
delete this.abc;
|
|
}
|
|
})()
|
|
`, "true")
|
|
}
|
|
|
|
func TestError(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
test(`new URIError() instanceof URIError`, "true")
|
|
test(`
|
|
var abc
|
|
try {
|
|
decodeURI("http://example.com/ _^#%")
|
|
}
|
|
catch (def) {
|
|
abc = def instanceof URIError
|
|
}
|
|
abc
|
|
`, "true")
|
|
}
|
|
|
|
func TestTo(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
|
|
{
|
|
value, _ := test(`"11"`).ToFloat()
|
|
Is(value, float64(11))
|
|
}
|
|
|
|
{
|
|
value, _ := test(`"11"`).ToInteger()
|
|
Is(value, int64(11))
|
|
|
|
value, _ = test(`1.1`).ToInteger()
|
|
Is(value, int64(1))
|
|
}
|
|
}
|
|
|
|
func TestShouldError(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
test(`raise:
|
|
xyzzy
|
|
throw new TypeError("Nothing happens.")
|
|
`, "ReferenceError: xyzzy is not defined")
|
|
}
|
|
|
|
func TestAPI(t *testing.T) {
|
|
Terst(t)
|
|
|
|
Otto, test := runTestWithOtto()
|
|
test(`
|
|
String.prototype.xyzzy = function(){
|
|
console.log(this)
|
|
return this.length + 11 + (arguments[0] || 0)
|
|
}
|
|
abc = new String("xyzzy")
|
|
def = "Nothing happens."
|
|
abc.xyzzy()
|
|
`, "16")
|
|
abc, _ := Otto.Get("abc")
|
|
def, _ := Otto.Get("def")
|
|
object := abc.Object()
|
|
result, _ := object.Call("xyzzy")
|
|
Is(result, "16")
|
|
result, _ = object.Call("xyzzy", 1)
|
|
Is(result, "17")
|
|
value, _ := object.Get("xyzzy")
|
|
result, _ = value.Call(def)
|
|
Is(result, "27")
|
|
result, _ = value.Call(def, 3)
|
|
Is(result, "30")
|
|
object = value.Object() // Object xyzzy
|
|
result, _ = object.Value().Call(def, 3)
|
|
Is(result, "30")
|
|
}
|
|
|
|
func TestUnicode(t *testing.T) {
|
|
Terst(t)
|
|
|
|
if false {
|
|
// TODO This test will fail because we handle strings internally the
|
|
// same way Go does, UTF-8
|
|
test := runTest()
|
|
test(`var abc = eval("\"a\uFFFFa\"");`)
|
|
test(`abc.length`, "3")
|
|
test(`abc != "aa"`, "true")
|
|
test("abc[1] === \"\uFFFF\"", "true")
|
|
dbg(utf8.RuneLen('\u000a'))
|
|
dbg(len(utf16.Encode([]rune("a\uFFFFa"))))
|
|
}
|
|
}
|
|
|
|
func TestDotMember(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
|
|
test(`
|
|
abc = {
|
|
ghi: 11,
|
|
}
|
|
abc.def = "Xyzzy"
|
|
abc.null = "Nothing happens."
|
|
`)
|
|
test(`abc.def`, "Xyzzy")
|
|
test(`abc.null`, "Nothing happens.")
|
|
test(`abc.ghi`, "11")
|
|
|
|
test(`
|
|
abc = {
|
|
null: 11,
|
|
}
|
|
`)
|
|
test(`abc.def`, "undefined")
|
|
test(`abc.null`, "11")
|
|
test(`abc.ghi`, "undefined")
|
|
}
|
|
|
|
func Test_stringToFloat(t *testing.T) {
|
|
Terst(t)
|
|
|
|
Is(stringToFloat("10e10000"), math.Inf(1))
|
|
Is(stringToFloat("10e10_."), "NaN")
|
|
}
|
|
|
|
func Test_delete(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
|
|
test(`
|
|
delete 42;
|
|
`, "true")
|
|
|
|
test(`
|
|
abc = delete $_undefined_$;
|
|
abc = abc && delete ($_undefined_$);
|
|
abc;
|
|
`, "true")
|
|
}
|
|
|
|
func TestObject_defineOwnProperty(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
|
|
test(`
|
|
var object = {};
|
|
|
|
var descriptor = new Boolean(false);
|
|
descriptor.configurable = true;
|
|
|
|
Object.defineProperties(object, {
|
|
property: descriptor
|
|
});
|
|
|
|
var abc = object.hasOwnProperty("property");
|
|
delete object.property;
|
|
var def = object.hasOwnProperty("property");
|
|
|
|
abc == true && def == false;
|
|
`, "true")
|
|
}
|
|
|
|
func Test_assignmentEvaluationOrder(t *testing.T) {
|
|
Terst(t)
|
|
|
|
test := runTest()
|
|
//test(`
|
|
// var abc = 0;
|
|
// ((abc = 1) & abc);
|
|
//`, "1")
|
|
|
|
test(`
|
|
var abc = 0;
|
|
(abc & (abc = 1));
|
|
`, "0")
|
|
}
|