Skip to content

Commit 10fb0a6

Browse files
authored
Encode large floats as exponent syntax (#441)
Otherwise round-tripping something like 5e+22 won't work.
1 parent 3d3abc2 commit 10fb0a6

File tree

2 files changed

+43
-37
lines changed

2 files changed

+43
-37
lines changed

encode.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ func (enc *Encoder) eElement(rv reflect.Value) {
297297
}
298298
enc.wf("inf")
299299
} else {
300-
enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32)))
300+
enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'g', -1, 32)))
301301
}
302302
case reflect.Float64:
303303
f := rv.Float()
@@ -312,7 +312,7 @@ func (enc *Encoder) eElement(rv reflect.Value) {
312312
}
313313
enc.wf("inf")
314314
} else {
315-
enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64)))
315+
enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'g', -1, 64)))
316316
}
317317
case reflect.Array, reflect.Slice:
318318
enc.eArrayOrSliceElement(rv)
@@ -330,10 +330,15 @@ func (enc *Encoder) eElement(rv reflect.Value) {
330330
// By the TOML spec, all floats must have a decimal with at least one number on
331331
// either side.
332332
func floatAddDecimal(fstr string) string {
333-
if !strings.Contains(fstr, ".") {
334-
return fstr + ".0"
333+
for _, c := range fstr {
334+
if c == 'e' { // Exponent syntax
335+
return fstr
336+
}
337+
if c == '.' {
338+
return fstr
339+
}
335340
}
336-
return fstr
341+
return fstr + ".0"
337342
}
338343

339344
func (enc *Encoder) writeQuoted(s string) {

encode_test.go

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,58 +7,59 @@ import (
77
"math"
88
"net"
99
"os"
10+
"reflect"
1011
"strconv"
1112
"strings"
1213
"testing"
1314
"time"
1415
)
1516

16-
func TestEncodeRoundTrip(t *testing.T) {
17-
type Config struct {
18-
Age int
19-
Cats []string
20-
Pi float64
21-
Perfection []int
22-
DOB time.Time
23-
Ipaddress net.IP
24-
}
17+
func TestRoundtrip(t *testing.T) {
18+
type scan struct {
19+
Age int `toml:"age"`
20+
Cats []string `toml:"cats"`
21+
Pi float64 `toml:"pi"`
22+
Perfection []int `toml:"perfection"`
23+
DOB time.Time `toml:"dob"`
24+
IP net.IP `toml:"ip"`
25+
LargeFloat float64 `toml:"large_float"`
26+
}
27+
28+
doc := `
29+
age = 13
30+
cats = ["one", "two", "three"]
31+
pi = 3.145
32+
perfection = [11, 2, 3, 4]
33+
dob = 2012-01-02T15:16:17Z
34+
ip = "192.168.59.254"
35+
large_float = 5e+22
36+
`[1:]
2537

26-
var inputs = Config{
38+
want := scan{
2739
Age: 13,
2840
Cats: []string{"one", "two", "three"},
2941
Pi: 3.145,
3042
Perfection: []int{11, 2, 3, 4},
31-
DOB: time.Now(),
32-
Ipaddress: net.ParseIP("192.168.59.254"),
43+
DOB: time.Date(2012, 01, 02, 15, 16, 17, 0, time.UTC),
44+
IP: net.ParseIP("192.168.59.254"),
45+
LargeFloat: 5e+22,
3346
}
3447

35-
var (
36-
firstBuffer bytes.Buffer
37-
secondBuffer bytes.Buffer
38-
outputs Config
39-
)
40-
err := NewEncoder(&firstBuffer).Encode(inputs)
41-
if err != nil {
42-
t.Fatal(err)
43-
}
44-
_, err = Decode(firstBuffer.String(), &outputs)
48+
var s scan
49+
_, err := Decode(doc, &s)
4550
if err != nil {
46-
t.Logf("Could not decode:\n%s\n", firstBuffer.String())
4751
t.Fatal(err)
4852
}
49-
err = NewEncoder(&secondBuffer).Encode(outputs)
50-
if err != nil {
51-
t.Fatal(err)
53+
if !reflect.DeepEqual(s, want) {
54+
t.Errorf("\nhave: %v\nwant: %v", s, want)
5255
}
53-
if firstBuffer.String() != secondBuffer.String() {
54-
t.Errorf("%s\n\nIS NOT IDENTICAL TO\n\n%s", firstBuffer.String(), secondBuffer.String())
55-
}
56-
out, err := Marshal(inputs)
56+
57+
out, err := Marshal(s)
5758
if err != nil {
5859
t.Fatal(err)
5960
}
60-
if firstBuffer.String() != string(out) {
61-
t.Errorf("%s\n\nIS NOT IDENTICAL TO\n\n%s", firstBuffer.String(), string(out))
61+
if string(out) != doc {
62+
t.Errorf("\nhave:\n%v\nwant:\n%v", string(out), doc)
6263
}
6364
}
6465

0 commit comments

Comments
 (0)