Browse Source

Always create a map when exporting. Fixes #422.

Dmitry Panov 3 years ago
parent
commit
fdb999e670
6 changed files with 104 additions and 6 deletions
  1. 1 3
      builtin_map.go
  2. 40 0
      builtin_map_test.go
  3. 1 0
      builtin_set.go
  4. 40 0
      builtin_set_test.go
  5. 1 3
      object.go
  6. 21 0
      object_goreflect_test.go

+ 1 - 3
builtin_map.go

@@ -68,9 +68,7 @@ func (mo *mapObject) export(ctx *objectExportCtx) interface{} {
 }
 }
 
 
 func (mo *mapObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
 func (mo *mapObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
-	if dst.IsNil() {
-		dst.Set(reflect.MakeMap(typ))
-	}
+	dst.Set(reflect.MakeMap(typ))
 	ctx.putTyped(mo.val, typ, dst.Interface())
 	ctx.putTyped(mo.val, typ, dst.Interface())
 	keyTyp := typ.Key()
 	keyTyp := typ.Key()
 	elemTyp := typ.Elem()
 	elemTyp := typ.Elem()

+ 40 - 0
builtin_map_test.go

@@ -62,6 +62,46 @@ func TestMapEvilIterator(t *testing.T) {
 	testScriptWithTestLib(SCRIPT, _undefined, t)
 	testScriptWithTestLib(SCRIPT, _undefined, t)
 }
 }
 
 
+func TestMapExportToNilMap(t *testing.T) {
+	vm := New()
+	var m map[int]interface{}
+	res, err := vm.RunString("new Map([[1, true]])")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = vm.ExportTo(res, &m)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(m) != 1 {
+		t.Fatal(m)
+	}
+	if _, exists := m[1]; !exists {
+		t.Fatal(m)
+	}
+}
+
+func TestMapExportToNonNilMap(t *testing.T) {
+	vm := New()
+	m := map[int]interface{}{
+		2: true,
+	}
+	res, err := vm.RunString("new Map([[1, true]])")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = vm.ExportTo(res, &m)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(m) != 1 {
+		t.Fatal(m)
+	}
+	if _, exists := m[1]; !exists {
+		t.Fatal(m)
+	}
+}
+
 func ExampleObject_Export_map() {
 func ExampleObject_Export_map() {
 	vm := New()
 	vm := New()
 	m, err := vm.RunString(`
 	m, err := vm.RunString(`

+ 1 - 0
builtin_set.go

@@ -89,6 +89,7 @@ func (so *setObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, c
 }
 }
 
 
 func (so *setObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
 func (so *setObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
+	dst.Set(reflect.MakeMap(typ))
 	keyTyp := typ.Key()
 	keyTyp := typ.Key()
 	elemTyp := typ.Elem()
 	elemTyp := typ.Elem()
 	iter := so.m.newIter()
 	iter := so.m.newIter()

+ 40 - 0
builtin_set_test.go

@@ -100,3 +100,43 @@ func TestSetExportToArrayMismatchedLengths(t *testing.T) {
 		t.Fatalf("unexpected error: %v", err)
 		t.Fatalf("unexpected error: %v", err)
 	}
 	}
 }
 }
+
+func TestSetExportToNilMap(t *testing.T) {
+	vm := New()
+	var m map[int]interface{}
+	res, err := vm.RunString("new Set([1])")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = vm.ExportTo(res, &m)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(m) != 1 {
+		t.Fatal(m)
+	}
+	if _, exists := m[1]; !exists {
+		t.Fatal(m)
+	}
+}
+
+func TestSetExportToNonNilMap(t *testing.T) {
+	vm := New()
+	m := map[int]interface{}{
+		2: true,
+	}
+	res, err := vm.RunString("new Set([1])")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = vm.ExportTo(res, &m)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(m) != 1 {
+		t.Fatal(m)
+	}
+	if _, exists := m[1]; !exists {
+		t.Fatal(m)
+	}
+}

+ 1 - 3
object.go

@@ -987,9 +987,7 @@ func (o *baseObject) exportType() reflect.Type {
 }
 }
 
 
 func genericExportToMap(o *Object, dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
 func genericExportToMap(o *Object, dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
-	if dst.IsNil() {
-		dst.Set(reflect.MakeMap(typ))
-	}
+	dst.Set(reflect.MakeMap(typ))
 	ctx.putTyped(o, typ, dst.Interface())
 	ctx.putTyped(o, typ, dst.Interface())
 	keyTyp := typ.Key()
 	keyTyp := typ.Key()
 	elemTyp := typ.Elem()
 	elemTyp := typ.Elem()

+ 21 - 0
object_goreflect_test.go

@@ -1244,3 +1244,24 @@ func TestGoReflectCopyOnWrite(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 }
 }
+
+func TestReflectOverwriteReflectMap(t *testing.T) {
+	vm := New()
+	type S struct {
+		M map[int]interface{}
+	}
+	var s S
+	s.M = map[int]interface{}{
+		0: true,
+	}
+	vm.Set("s", &s)
+	_, err := vm.RunString(`
+	s.M = {1: false};
+	`)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if _, exists := s.M[0]; exists {
+		t.Fatal(s)
+	}
+}