From 38c5fd5cf872cf2eabad1361342097e11d292c91 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 25 Sep 2015 16:35:54 -0700 Subject: [PATCH] math/big: implement Float.Text(Un)Marshaler Fixes #12256. Change-Id: Ie4a3337996da5c060b27530b076048ffead85f3b Reviewed-on: https://go-review.googlesource.com/15040 Reviewed-by: Alan Donovan --- src/math/big/floatmarsh.go | 33 ++++++++++++++++++++ src/math/big/floatmarsh_test.go | 54 +++++++++++++++++++++++++++++++++ src/math/big/intmarsh.go | 27 ++++++----------- src/math/big/intmarsh_test.go | 6 +++- src/math/big/ratmarsh.go | 8 ++--- src/math/big/ratmarsh_test.go | 4 ++- 6 files changed, 109 insertions(+), 23 deletions(-) create mode 100644 src/math/big/floatmarsh.go create mode 100644 src/math/big/floatmarsh_test.go diff --git a/src/math/big/floatmarsh.go b/src/math/big/floatmarsh.go new file mode 100644 index 0000000000..44987ee03a --- /dev/null +++ b/src/math/big/floatmarsh.go @@ -0,0 +1,33 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements encoding/decoding of Floats. + +package big + +import "fmt" + +// MarshalText implements the encoding.TextMarshaler interface. +// Only the Float value is marshaled (in full precision), other +// attributes such as precision or accuracy are ignored. +func (x *Float) MarshalText() (text []byte, err error) { + if x == nil { + return []byte(""), nil + } + var buf []byte + return x.Append(buf, 'g', -1), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The result is rounded per the precision and rounding mode of z. +// If z's precision is 0, it is changed to 64 before rounding takes +// effect. +func (z *Float) UnmarshalText(text []byte) error { + // TODO(gri): get rid of the []byte/string conversion + _, _, err := z.Parse(string(text), 0) + if err != nil { + err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err) + } + return err +} diff --git a/src/math/big/floatmarsh_test.go b/src/math/big/floatmarsh_test.go new file mode 100644 index 0000000000..d7ef2fca68 --- /dev/null +++ b/src/math/big/floatmarsh_test.go @@ -0,0 +1,54 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "encoding/json" + "testing" +) + +var floatVals = []string{ + "0", + "1", + "0.1", + "2.71828", + "1234567890", + "3.14e1234", + "3.14e-1234", + "0.738957395793475734757349579759957975985497e100", + "0.73895739579347546656564656573475734957975995797598589749859834759476745986795497e100", + "inf", + "Inf", +} + +func TestFloatJSONEncoding(t *testing.T) { + for _, test := range floatVals { + for _, sign := range []string{"", "+", "-"} { + for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} { + x := sign + test + var tx Float + _, _, err := tx.SetPrec(prec).Parse(x, 0) + if err != nil { + t.Errorf("parsing of %s (prec = %d) failed (invalid test case): %v", x, prec, err) + continue + } + b, err := json.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %v (prec = %d) failed: %v", &tx, prec, err) + continue + } + var rx Float + rx.SetPrec(prec) + if err := json.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %v (prec = %d) failed: %v", &tx, prec, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("JSON encoding of %v (prec = %d) failed: got %v want %v", &tx, prec, &rx, &tx) + } + } + } + } +} diff --git a/src/math/big/intmarsh.go b/src/math/big/intmarsh.go index ec1eeb4003..e6eed1309b 100644 --- a/src/math/big/intmarsh.go +++ b/src/math/big/intmarsh.go @@ -42,23 +42,6 @@ func (z *Int) GobDecode(buf []byte) error { return nil } -// MarshalJSON implements the json.Marshaler interface. -func (x *Int) MarshalJSON() ([]byte, error) { - if x == nil { - return []byte(""), nil - } - return x.abs.itoa(x.neg, 10), nil -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (z *Int) UnmarshalJSON(text []byte) error { - // TODO(gri): get rid of the []byte/string conversion - if _, ok := z.SetString(string(text), 0); !ok { - return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text) - } - return nil -} - // MarshalText implements the encoding.TextMarshaler interface. func (x *Int) MarshalText() (text []byte, err error) { if x == nil { @@ -75,3 +58,13 @@ func (z *Int) UnmarshalText(text []byte) error { } return nil } + +// MarshalJSON implements the json.Marshaler interface. +func (x *Int) MarshalJSON() ([]byte, error) { + return x.MarshalText() +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (z *Int) UnmarshalJSON(text []byte) error { + return z.UnmarshalText(text) +} diff --git a/src/math/big/intmarsh_test.go b/src/math/big/intmarsh_test.go index c992f1c915..20ce273323 100644 --- a/src/math/big/intmarsh_test.go +++ b/src/math/big/intmarsh_test.go @@ -37,10 +37,12 @@ func TestIntGobEncoding(t *testing.T) { tx.SetString(test, 10) if err := enc.Encode(&tx); err != nil { t.Errorf("encoding of %s failed: %s", &tx, err) + continue } var rx Int if err := dec.Decode(&rx); err != nil { t.Errorf("decoding of %s failed: %s", &tx, err) + continue } if rx.Cmp(&tx) != 0 { t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx) @@ -70,7 +72,7 @@ func TestGobEncodingNilIntInSlice(t *testing.T) { } var zero Int if out[0].Cmp(&zero) != 0 { - t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out) + t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out) } } @@ -81,10 +83,12 @@ func TestIntJSONEncoding(t *testing.T) { b, err := json.Marshal(&tx) if err != nil { t.Errorf("marshaling of %s failed: %s", &tx, err) + continue } var rx Int if err := json.Unmarshal(b, &rx); err != nil { t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue } if rx.Cmp(&tx) != 0 { t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx) diff --git a/src/math/big/ratmarsh.go b/src/math/big/ratmarsh.go index 6bb9d8af60..b82e8d4ae8 100644 --- a/src/math/big/ratmarsh.go +++ b/src/math/big/ratmarsh.go @@ -58,15 +58,15 @@ func (z *Rat) GobDecode(buf []byte) error { } // MarshalText implements the encoding.TextMarshaler interface. -func (r *Rat) MarshalText() (text []byte, err error) { +func (x *Rat) MarshalText() (text []byte, err error) { // TODO(gri): get rid of the []byte/string conversion - return []byte(r.RatString()), nil + return []byte(x.RatString()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface. -func (r *Rat) UnmarshalText(text []byte) error { +func (z *Rat) UnmarshalText(text []byte) error { // TODO(gri): get rid of the []byte/string conversion - if _, ok := r.SetString(string(text)); !ok { + if _, ok := z.SetString(string(text)); !ok { return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text) } return nil diff --git a/src/math/big/ratmarsh_test.go b/src/math/big/ratmarsh_test.go index 2e91e38e11..351d109f8d 100644 --- a/src/math/big/ratmarsh_test.go +++ b/src/math/big/ratmarsh_test.go @@ -22,10 +22,12 @@ func TestRatGobEncoding(t *testing.T) { tx.SetString(test + ".14159265") if err := enc.Encode(&tx); err != nil { t.Errorf("encoding of %s failed: %s", &tx, err) + continue } var rx Rat if err := dec.Decode(&rx); err != nil { t.Errorf("decoding of %s failed: %s", &tx, err) + continue } if rx.Cmp(&tx) != 0 { t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx) @@ -55,7 +57,7 @@ func TestGobEncodingNilRatInSlice(t *testing.T) { } var zero Rat if out[0].Cmp(&zero) != 0 { - t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out) + t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out) } } -- 2.48.1