From 2bd767b1022dd3254bcec469f0ee164024726486 Mon Sep 17 00:00:00 2001 From: Richard Musiol Date: Thu, 28 Mar 2019 01:22:37 +0100 Subject: [PATCH] syscall/js: improve Value.String() for non-string values This change modifies Value.String() to use the following representations for non-string values: It avoids JavaScript conversion semantics in the Go API and lowers the risk of hidden bugs by unexpected conversions, e.g. the conversion of the number 42 to the string "42". See discussion in #29642. This is a breaking change, which are still allowed for syscall/js. The impact should be small since it only affects uses of Value.String() with non-string values, which should be uncommon. Updates #29642. Change-Id: I2c27be6e24befe8cb713031fbf66f7b6041e7148 Reviewed-on: https://go-review.googlesource.com/c/go/+/169757 Run-TryBot: Richard Musiol TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/syscall/js/js.go | 30 ++++++++++++++++++++++++++++-- src/syscall/js/js_test.go | 24 ++++++++++++++++++++---- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/syscall/js/js.go b/src/syscall/js/js.go index bccf188fa5..0acc7da9bf 100644 --- a/src/syscall/js/js.go +++ b/src/syscall/js/js.go @@ -422,9 +422,35 @@ func (v Value) Truthy() bool { } } -// String returns the value v converted to string according to JavaScript type conversions. +// String returns the value v as a string. +// String is a special case because of Go's String method convention. Unlike the other getters, +// it does not panic if v's Type is not TypeString. Instead, it returns a string of the form "" +// or "" where T is v's type and V is a string representation of v's value. func (v Value) String() string { - str, length := valuePrepareString(v.ref) + switch v.Type() { + case TypeString: + return jsString(v.ref) + case TypeUndefined: + return "" + case TypeNull: + return "" + case TypeBoolean: + return "" + case TypeNumber: + return "" + case TypeSymbol: + return "" + case TypeObject: + return "" + case TypeFunction: + return "" + default: + panic("bad type") + } +} + +func jsString(v ref) string { + str, length := valuePrepareString(v) b := make([]byte, length) valueLoadString(str, b) return string(b) diff --git a/src/syscall/js/js_test.go b/src/syscall/js/js_test.go index 594284faf9..20ccac7779 100644 --- a/src/syscall/js/js_test.go +++ b/src/syscall/js/js_test.go @@ -72,10 +72,26 @@ func TestString(t *testing.T) { t.Errorf("same value not equal") } - wantInt := "42" - o = dummys.Get("someInt") - if got := o.String(); got != wantInt { - t.Errorf("got %#v, want %#v", got, wantInt) + if got, want := js.Undefined().String(), ""; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.Null().String(), ""; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.ValueOf(true).String(), ""; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.ValueOf(42.5).String(), ""; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.Global().Call("Symbol").String(), ""; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.Global().String(), ""; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.Global().Get("setTimeout").String(), ""; got != want { + t.Errorf("got %#v, want %#v", got, want) } } -- 2.50.0