Skip to content
This repository has been archived by the owner on Oct 6, 2021. It is now read-only.

Commit

Permalink
Fixed bugs in Array.prototype.sort(), Object.assign() and Date.protot…
Browse files Browse the repository at this point in the history
…ype.toJSON()
  • Loading branch information
dop251 committed Aug 11, 2020
1 parent 28cf031 commit 3ec8e20
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 8 deletions.
13 changes: 9 additions & 4 deletions builtin_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func (r *Runtime) arrayproto_pop(call FunctionCall) Value {
func (r *Runtime) arrayproto_join(call FunctionCall) Value {
o := call.This.ToObject(r)
l := int(toLength(o.self.getStr("length", nil)))
var sep valueString = asciiString("")
var sep valueString
if s := call.Argument(0); s != _undefined {
sep = s.toString()
} else {
Expand Down Expand Up @@ -334,9 +334,14 @@ func (r *Runtime) arrayproto_sort(call FunctionCall) Value {
o := call.This.ToObject(r)

var compareFn func(FunctionCall) Value

if arg, ok := call.Argument(0).(*Object); ok {
compareFn, _ = arg.self.assertCallable()
arg := call.Argument(0)
if arg != _undefined {
if arg, ok := call.Argument(0).(*Object); ok {
compareFn, _ = arg.self.assertCallable()
}
if compareFn == nil {
panic(r.NewTypeError("The comparison function must be either a function or undefined"))
}
}

ctx := arraySortCtx{
Expand Down
46 changes: 46 additions & 0 deletions builtin_arrray_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,49 @@ func TestUnscopables(t *testing.T) {
`
testScript1(SCRIPT, valueTrue, t)
}

func TestArraySort(t *testing.T) {
const SCRIPT = `
assert.throws(TypeError, function() {
[1,2].sort(null);
}, "null compare function");
assert.throws(TypeError, function() {
[1,2].sort({});
}, "non-callable compare function");
`
testScript1(TESTLIB+SCRIPT, _undefined, t)
}

func TestArrayConcat(t *testing.T) {
const SCRIPT = `
var concat = Array.prototype.concat;
var array = [1, 2];
var sparseArray = [1, , 2];
var nonSpreadableArray = [1, 2];
nonSpreadableArray[Symbol.isConcatSpreadable] = false;
var arrayLike = { 0: 1, 1: 2, length: 2 };
var spreadableArrayLike = { 0: 1, 1: 2, length: 2 };
spreadableArrayLike[Symbol.isConcatSpreadable] = true;
assert(looksNative(concat));
assert(deepEqual(array.concat(), [1, 2]), '#1');
assert(deepEqual(sparseArray.concat(), [1, , 2]), '#2');
assert(deepEqual(nonSpreadableArray.concat(), [[1, 2]]), '#3');
assert(deepEqual(concat.call(arrayLike), [{ 0: 1, 1: 2, length: 2 }]), '#4');
assert(deepEqual(concat.call(spreadableArrayLike), [1, 2]), '#5');
assert(deepEqual([].concat(array), [1, 2]), '#6');
assert(deepEqual([].concat(sparseArray), [1, , 2]), '#7');
assert(deepEqual([].concat(nonSpreadableArray), [[1, 2]]), '#8');
assert(deepEqual([].concat(arrayLike), [{ 0: 1, 1: 2, length: 2 }]), '#9');
assert(deepEqual([].concat(spreadableArrayLike), [1, 2]), '#10');
assert(deepEqual(array.concat(sparseArray, nonSpreadableArray, arrayLike, spreadableArrayLike), [
1, 2, 1, , 2, [1, 2], { 0: 1, 1: 2, length: 2 }, 1, 2,
]), '#11');
array = [];
array.constructor = {};
array.constructor[Symbol.species] = function () {
return { foo: 1 };
}
assert.sameValue(array.concat().foo, 1, '@@species');
`
testScript1(TESTLIBX+SCRIPT, _undefined, t)
}
2 changes: 0 additions & 2 deletions builtin_date.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ func (r *Runtime) dateproto_toJSON(call FunctionCall) Value {
if math.IsNaN(f) || math.IsInf(f, 0) {
return _null
}
} else if _, ok := tv.(valueInt); !ok {
return _null
}

if toISO, ok := obj.self.getStr("toISOString", nil).(*Object); ok {
Expand Down
5 changes: 4 additions & 1 deletion builtin_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,12 +453,15 @@ func (r *Runtime) object_assign(call FunctionCall) Value {
for _, arg := range call.Arguments[1:] {
if arg != _undefined && arg != _null {
source := arg.ToObject(r)
for _, key := range source.self.ownPropertyKeys(false, nil) {
for _, key := range source.self.ownPropertyKeys(true, nil) {
p := source.getOwnProp(key)
if p == nil {
continue
}
if v, ok := p.(*valueProperty); ok {
if !v.enumerable {
continue
}
p = v.get(source)
}
to.setOwn(key, p, true)
Expand Down
2 changes: 1 addition & 1 deletion builtin_typedarrays.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ func (r *Runtime) typedArrayProto_join(call FunctionCall) Value {
if ta, ok := r.toObject(call.This).self.(*typedArrayObject); ok {
ta.viewedArrayBuf.ensureNotDetached()
s := call.Argument(0)
sep := stringEmpty
var sep valueString
if s != _undefined {
sep = s.toString()
} else {
Expand Down
43 changes: 43 additions & 0 deletions date_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,43 @@ function compareArray(a, b) {
}
return true;
}
`

const TESTLIBX = TESTLIB +
`function looksNative(fn) {
return /native code/.test(Function.prototype.toString.call(fn));
}
function deepEqual(a, b) {
if (typeof a === "object") {
if (typeof b === "object") {
if (a === b) {
return true;
}
if (Reflect.getPrototypeOf(a) !== Reflect.getPrototypeOf(b)) {
return false;
}
var keysA = Object.keys(a);
var keysB = Object.keys(b);
if (keysA.length !== keysB.length) {
return false;
}
if (!compareArray(keysA.sort(), keysB.sort())) {
return false;
}
for (var i = 0; i < keysA.length; i++) {
var key = keysA[i];
if (!deepEqual(a[key], b[key])) {
return false;
}
}
return true;
} else {
return false;
}
}
return assert._isSameValue(a, b);
}
`

func TestDateUTC(t *testing.T) {
Expand Down Expand Up @@ -396,3 +432,10 @@ func TestDateExport(t *testing.T) {
t.Fatalf("Invalid export type: %T", exp)
}
}

func TestDateToJSON(t *testing.T) {
const SCRIPT = `
Date.prototype.toJSON.call({ toISOString: function () { return 1; } })
`
testScript1(SCRIPT, intToValue(1), t)
}
16 changes: 16 additions & 0 deletions object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ func TestDefinePropertiesSymbol(t *testing.T) {
testScript1(SCRIPT, valueTrue, t)
}

func TestObjectAssign(t *testing.T) {
const SCRIPT = `
assert.sameValue(Object.assign({ b: 1 }, { get a() {
Object.defineProperty(this, "b", {
value: 3,
enumerable: false
});
}, b: 2 }).b, 1, "#1");
assert.sameValue(Object.assign({ b: 1 }, { get a() {
delete this.b;
}, b: 2 }).b, 1, "#2");
`
testScript1(TESTLIB+SCRIPT, _undefined, t)
}

func BenchmarkPut(b *testing.B) {
v := &Object{}

Expand Down
9 changes: 9 additions & 0 deletions regexp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,15 @@ func TestRegexpInit(t *testing.T) {
testScript1(SCRIPT, intToValue(0), t)
}

func TestRegexpToString(t *testing.T) {
const SCRIPT = `
RegExp.prototype.toString.call({
source: 'foo',
flags: 'bar'});
`
testScript1(SCRIPT, asciiString("/foo/bar"), t)
}

func BenchmarkRegexpSplitWithBackRef(b *testing.B) {
const SCRIPT = `
"aaaaaaaaaaaaaaaaaaaaaaaaa++bbbbbbbbbbbbbbbbbbbbbb+-ccccccccccccccccccccccc".split(/([+-])\1/)
Expand Down

0 comments on commit 3ec8e20

Please sign in to comment.