1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package big
6
7import (
8	"bytes"
9	"encoding/gob"
10	"encoding/json"
11	"io"
12	"strings"
13	"testing"
14)
15
16var floatVals = []string{
17	"0",
18	"1",
19	"0.1",
20	"2.71828",
21	"1234567890",
22	"3.14e1234",
23	"3.14e-1234",
24	"0.738957395793475734757349579759957975985497e100",
25	"0.73895739579347546656564656573475734957975995797598589749859834759476745986795497e100",
26	"inf",
27	"Inf",
28}
29
30func TestFloatGobEncoding(t *testing.T) {
31	var medium bytes.Buffer
32	enc := gob.NewEncoder(&medium)
33	dec := gob.NewDecoder(&medium)
34	for _, test := range floatVals {
35		for _, sign := range []string{"", "+", "-"} {
36			for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} {
37				for _, mode := range []RoundingMode{ToNearestEven, ToNearestAway, ToZero, AwayFromZero, ToNegativeInf, ToPositiveInf} {
38					medium.Reset() // empty buffer for each test case (in case of failures)
39					x := sign + test
40
41					var tx Float
42					_, _, err := tx.SetPrec(prec).SetMode(mode).Parse(x, 0)
43					if err != nil {
44						t.Errorf("parsing of %s (%dbits, %v) failed (invalid test case): %v", x, prec, mode, err)
45						continue
46					}
47
48					// If tx was set to prec == 0, tx.Parse(x, 0) assumes precision 64. Correct it.
49					if prec == 0 {
50						tx.SetPrec(0)
51					}
52
53					if err := enc.Encode(&tx); err != nil {
54						t.Errorf("encoding of %v (%dbits, %v) failed: %v", &tx, prec, mode, err)
55						continue
56					}
57
58					var rx Float
59					if err := dec.Decode(&rx); err != nil {
60						t.Errorf("decoding of %v (%dbits, %v) failed: %v", &tx, prec, mode, err)
61						continue
62					}
63
64					if rx.Cmp(&tx) != 0 {
65						t.Errorf("transmission of %s failed: got %s want %s", x, rx.String(), tx.String())
66						continue
67					}
68
69					if rx.Prec() != prec {
70						t.Errorf("transmission of %s's prec failed: got %d want %d", x, rx.Prec(), prec)
71					}
72
73					if rx.Mode() != mode {
74						t.Errorf("transmission of %s's mode failed: got %s want %s", x, rx.Mode(), mode)
75					}
76
77					if rx.Acc() != tx.Acc() {
78						t.Errorf("transmission of %s's accuracy failed: got %s want %s", x, rx.Acc(), tx.Acc())
79					}
80				}
81			}
82		}
83	}
84}
85
86func TestFloatCorruptGob(t *testing.T) {
87	var buf bytes.Buffer
88	tx := NewFloat(4 / 3).SetPrec(1000).SetMode(ToPositiveInf)
89	if err := gob.NewEncoder(&buf).Encode(tx); err != nil {
90		t.Fatal(err)
91	}
92	b := buf.Bytes()
93
94	var rx Float
95	if err := gob.NewDecoder(bytes.NewReader(b)).Decode(&rx); err != nil {
96		t.Fatal(err)
97	}
98
99	if err := gob.NewDecoder(bytes.NewReader(b[:10])).Decode(&rx); err != io.ErrUnexpectedEOF {
100		t.Errorf("got %v want EOF", err)
101	}
102
103	b[1] = 0
104	if err := gob.NewDecoder(bytes.NewReader(b)).Decode(&rx); err == nil {
105		t.Fatal("got nil want version error")
106	}
107}
108
109func TestFloatJSONEncoding(t *testing.T) {
110	for _, test := range floatVals {
111		for _, sign := range []string{"", "+", "-"} {
112			for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} {
113				if prec > 53 && testing.Short() {
114					continue
115				}
116				x := sign + test
117				var tx Float
118				_, _, err := tx.SetPrec(prec).Parse(x, 0)
119				if err != nil {
120					t.Errorf("parsing of %s (prec = %d) failed (invalid test case): %v", x, prec, err)
121					continue
122				}
123				b, err := json.Marshal(&tx)
124				if err != nil {
125					t.Errorf("marshaling of %v (prec = %d) failed: %v", &tx, prec, err)
126					continue
127				}
128				var rx Float
129				rx.SetPrec(prec)
130				if err := json.Unmarshal(b, &rx); err != nil {
131					t.Errorf("unmarshaling of %v (prec = %d) failed: %v", &tx, prec, err)
132					continue
133				}
134				if rx.Cmp(&tx) != 0 {
135					t.Errorf("JSON encoding of %v (prec = %d) failed: got %v want %v", &tx, prec, &rx, &tx)
136				}
137			}
138		}
139	}
140}
141
142func TestFloatGobDecodeShortBuffer(t *testing.T) {
143	for _, tc := range [][]byte{
144		[]byte{0x1, 0x0, 0x0, 0x0},
145		[]byte{0x1, 0xfa, 0x0, 0x0, 0x0, 0x0},
146	} {
147		err := NewFloat(0).GobDecode(tc)
148		if err == nil {
149			t.Error("expected GobDecode to return error for malformed input")
150		}
151	}
152}
153
154func TestFloatGobDecodeInvalid(t *testing.T) {
155	for _, tc := range []struct {
156		buf []byte
157		msg string
158	}{
159		{
160			[]byte{0x1, 0x2a, 0x20, 0x20, 0x20, 0x20, 0x0, 0x20, 0x20, 0x20, 0x0, 0x20, 0x20, 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0xc},
161			"Float.GobDecode: msb not set in last word",
162		},
163		{
164			[]byte{1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
165			"Float.GobDecode: nonzero finite number with empty mantissa",
166		},
167	} {
168		err := NewFloat(0).GobDecode(tc.buf)
169		if err == nil || !strings.HasPrefix(err.Error(), tc.msg) {
170			t.Errorf("expected GobDecode error prefix: %s, got: %v", tc.msg, err)
171		}
172	}
173}
174