ai_old/goja/array_sparse_test.go
2024-09-20 16:50:35 +08:00

265 lines
5.5 KiB
Go

package goja
import (
"testing"
)
func TestSparseArraySetLengthWithPropItems(t *testing.T) {
const SCRIPT = `
var a = [1,2,3,4];
a[100000] = 5;
var thrown = false;
Object.defineProperty(a, "2", {value: 42, configurable: false, writable: false});
try {
Object.defineProperty(a, "length", {value: 0, writable: false});
} catch (e) {
thrown = e instanceof TypeError;
}
thrown && a.length === 3;
`
testScript(SCRIPT, valueTrue, t)
}
func TestSparseArraySwitch(t *testing.T) {
vm := New()
_, err := vm.RunString(`
var a = [];
a[20470] = 5; // switch to sparse`)
if err != nil {
t.Fatal(err)
}
a := vm.Get("a").(*Object)
if _, ok := a.self.(*sparseArrayObject); !ok {
t.Fatal("1: array is not sparse")
}
_, err = vm.RunString(`
var cutoffIdx = Math.round(20470 - 20470/8);
for (var i = a.length - 1; i >= cutoffIdx; i--) {
a[i] = i;
}
// At this point it will have switched to a normal array
if (a.length != 20471) {
throw new Error("Invalid length: " + a.length);
}
for (var i = 0; i < cutoffIdx; i++) {
if (a[i] !== undefined) {
throw new Error("Invalid value at " + i + ": " + a[i]);
}
}
for (var i = cutoffIdx; i < a.length; i++) {
if (a[i] !== i) {
throw new Error("Invalid value at " + i + ": " + a[i]);
}
}`)
if err != nil {
t.Fatal(err)
}
if _, ok := a.self.(*arrayObject); !ok {
t.Fatal("2: array is not normal")
}
_, err = vm.RunString(`
// Now try to expand. Should stay a normal array
a[20471] = 20471;
if (a.length != 20472) {
throw new Error("Invalid length: " + a.length);
}
for (var i = 0; i < cutoffIdx; i++) {
if (a[i] !== undefined) {
throw new Error("Invalid value at " + i + ": " + a[i]);
}
}
for (var i = cutoffIdx; i < a.length; i++) {
if (a[i] !== i) {
throw new Error("Invalid value at " + i + ": " + a[i]);
}
}`)
if err != nil {
t.Fatal(err)
}
if _, ok := a.self.(*arrayObject); !ok {
t.Fatal("3: array is not normal")
}
_, err = vm.RunString(`
// Delete enough elements for it to become sparse again.
var cutoffIdx1 = Math.round(20472 - 20472/10);
for (var i = cutoffIdx; i < cutoffIdx1; i++) {
delete a[i];
}
// This should switch it back to sparse.
a[25590] = 25590;
if (a.length != 25591) {
throw new Error("Invalid length: " + a.length);
}
for (var i = 0; i < cutoffIdx1; i++) {
if (a[i] !== undefined) {
throw new Error("Invalid value at " + i + ": " + a[i]);
}
}
for (var i = cutoffIdx1; i < 20472; i++) {
if (a[i] !== i) {
throw new Error("Invalid value at " + i + ": " + a[i]);
}
}
for (var i = 20472; i < 25590; i++) {
if (a[i] !== undefined) {
throw new Error("Invalid value at " + i + ": " + a[i]);
}
}
if (a[25590] !== 25590) {
throw new Error("Invalid value at 25590: " + a[25590]);
}
`)
if err != nil {
t.Fatal(err)
}
if _, ok := a.self.(*sparseArrayObject); !ok {
t.Fatal("4: array is not sparse")
}
}
func TestSparseArrayOwnKeys(t *testing.T) {
const SCRIPT = `
var a1 = [];
a1[500000] = 1;
var seen = false;
var count = 0;
var keys = Object.keys(a1);
keys.length === 1 && keys[0] === "500000";
`
testScript(SCRIPT, valueTrue, t)
}
func TestSparseArrayEnumerate(t *testing.T) {
const SCRIPT = `
var a1 = [];
a1[500000] = 1;
var seen = false;
var count = 0;
for (var i in a1) {
if (i === "500000") {
if (seen) {
throw new Error("seen twice");
}
seen = true;
}
count++;
}
seen && count === 1;
`
testScript(SCRIPT, valueTrue, t)
}
func TestArraySparseMaxLength(t *testing.T) {
const SCRIPT = `
var a = [];
a[4294967294]=1;
a.length === 4294967295 && a[4294967294] === 1;
`
testScript(SCRIPT, valueTrue, t)
}
func TestArraySparseExportProps(t *testing.T) {
vm := New()
proto := vm.NewArray()
for _, idx := range []string{"0", "500", "9999", "10001", "20471"} {
err := proto.Set(idx, true)
if err != nil {
t.Fatal(err)
}
}
arr := vm.NewArray()
err := arr.SetPrototype(proto)
if err != nil {
t.Fatal(err)
}
err = arr.DefineDataProperty("20470", vm.ToValue(true), FLAG_TRUE, FLAG_FALSE, FLAG_TRUE)
if err != nil {
t.Fatal(err)
}
err = arr.DefineDataProperty("10000", vm.ToValue(true), FLAG_TRUE, FLAG_FALSE, FLAG_TRUE)
if err != nil {
t.Fatal(err)
}
err = arr.Set("length", 20472)
if err != nil {
t.Fatal(err)
}
actual := arr.Export()
if actualArr, ok := actual.([]interface{}); ok {
if len(actualArr) == 20472 {
expectedIdx := map[int]struct{}{
0: {},
500: {},
9999: {},
10000: {},
10001: {},
20470: {},
20471: {},
}
for i, v := range actualArr {
if _, exists := expectedIdx[i]; exists {
if v != true {
t.Fatalf("Expected true at %d, got %v", i, v)
}
} else {
if v != nil {
t.Fatalf("Expected nil at %d, got %v", i, v)
}
}
}
} else {
t.Fatalf("Expected len 20471, actual: %d", len(actualArr))
}
} else {
t.Fatalf("Invalid export type: %T", actual)
}
}
func TestSparseArrayExportToSlice(t *testing.T) {
vm := New()
arr := vm.NewArray()
err := arr.Set("20470", 120470)
if err != nil {
t.Fatal(err)
}
err = arr.DefineDataProperty("20471", vm.ToValue(220471), FLAG_TRUE, FLAG_FALSE, FLAG_TRUE)
if err != nil {
t.Fatal(err)
}
var exp []int
err = vm.ExportTo(arr, &exp)
if err != nil {
t.Fatal(err)
}
if len(exp) != 20472 {
t.Fatalf("len: %d", len(exp))
}
if e := exp[20470]; e != 120470 {
t.Fatalf("20470: %d", e)
}
if e := exp[20471]; e != 220471 {
t.Fatalf("20471: %d", e)
}
for i := 0; i < 20470; i++ {
if exp[i] != 0 {
t.Fatalf("at %d: %d", i, exp[i])
}
}
}