142 lines
4.1 KiB
Go
142 lines
4.1 KiB
Go
package toml
|
|
|
|
import (
|
|
"math"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestCheckedNumericConversions(t *testing.T) {
|
|
type Count uint64
|
|
tests := []struct {
|
|
value any
|
|
target any
|
|
want any
|
|
valid bool
|
|
}{
|
|
{uint(42), new(int64), int64(42), true},
|
|
{Count(math.MaxUint64), new(uint64), uint64(math.MaxUint64), true},
|
|
{uint64(math.MaxUint64), new(int64), nil, false},
|
|
{int64(-1), new(uint64), nil, false},
|
|
{float64(0x1p63), new(int64), nil, false},
|
|
{float64(-0x1p63), new(int64), int64(math.MinInt64), true},
|
|
{float64(0x1p64), new(uint64), nil, false},
|
|
{1.5, new(int), nil, false},
|
|
{math.NaN(), new(int), nil, false},
|
|
{math.Inf(1), new(uint64), nil, false},
|
|
{float32(12), new(uint8), uint8(12), true},
|
|
{uint64(1<<53) + 1, new(float64), nil, false},
|
|
{int64(1<<24) + 1, new(float32), nil, false},
|
|
{uint64(1 << 63), new(float64), float64(1 << 63), true},
|
|
{1e100, new(float32), nil, false},
|
|
}
|
|
for _, tt := range tests {
|
|
err := Decode(tt.value, tt.target)
|
|
if (err == nil) != tt.valid {
|
|
t.Errorf("%v (%T) -> %T: %v", tt.value, tt.value, tt.target, err)
|
|
}
|
|
if tt.valid && !reflect.DeepEqual(reflect.ValueOf(tt.target).Elem().Interface(), tt.want) {
|
|
t.Errorf("got %v, want %v", tt.target, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecodeTransactionAndNamedKeys(t *testing.T) {
|
|
type Key string
|
|
var m map[Key]int
|
|
if err := Decode(map[string]any{"x": 4}, &m); err != nil || m["x"] != 4 {
|
|
t.Fatalf("%v %#v", err, m)
|
|
}
|
|
type C struct {
|
|
First int `toml:",omitempty"`
|
|
Second int8
|
|
}
|
|
c := C{7, 8}
|
|
if err := Decode(map[string]any{"First": 11, "Second": 400}, &c); err == nil || c != (C{7, 8}) {
|
|
t.Fatalf("partial update: %+v %v", c, err)
|
|
}
|
|
if err := Decode(map[string]any{"First": 11}, &c); err != nil || c.First != 11 {
|
|
t.Fatalf("empty tag name: %+v %v", c, err)
|
|
}
|
|
}
|
|
|
|
func TestRoundTripSupportedValues(t *testing.T) {
|
|
input := map[string]any{
|
|
"dot.key": map[string]any{"quoted\"key": map[string]any{"x": "\b\f\x00\x7f界"}},
|
|
"items": []any{map[string]any{"x": int64(3)}, map[string]any{"x": int64(4)}},
|
|
"nested": []any{[]any{map[string]any{"x": true}}},
|
|
"mixed": []any{int64(1), map[string]any{"y": "text"}},
|
|
}
|
|
data, err := Marshal(input)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := NewParser(data).Parse()
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", data, err)
|
|
}
|
|
if !reflect.DeepEqual(normalize(input), normalize(got)) {
|
|
t.Fatalf("round trip: %#v", got)
|
|
}
|
|
}
|
|
|
|
func TestMarshalRejectsInvalidValues(t *testing.T) {
|
|
cycle := map[string]any{}
|
|
cycle["self"] = cycle
|
|
for _, value := range []any{
|
|
map[string]any{"u": uint64(math.MaxUint64)},
|
|
map[string]any{"s": string([]byte{0xff})},
|
|
map[string]any{"123": 1},
|
|
struct {
|
|
A int `toml:"x"`
|
|
B int `toml:"x"`
|
|
}{},
|
|
cycle,
|
|
} {
|
|
if _, err := Marshal(value); err == nil {
|
|
t.Errorf("invalid %T accepted", value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseBoundariesAndSyntax(t *testing.T) {
|
|
m, err := NewParser([]byte("min = -9223372036854775808\nmax = 9223372036854775807")).Parse()
|
|
if err != nil || m["min"] != int64(math.MinInt64) || m["max"] != int64(math.MaxInt64) {
|
|
t.Fatalf("%#v %v", m, err)
|
|
}
|
|
for _, s := range []string{"x=9223372036854775808", "x=1 y=2", "[x] y=2", "x=[1\n2]", "x={a=1\nb=2}", "x=\"\x00\"", "x=\"\xff\"", "[" + strings.Repeat("a.", 1100) + "b]"} {
|
|
if _, err := NewParser([]byte(s)).Parse(); err == nil {
|
|
t.Errorf("accepted invalid input %q", s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func FuzzIntegerConversions(f *testing.F) {
|
|
f.Add(uint64(math.MaxUint64))
|
|
f.Add(uint64(1<<53) + 1)
|
|
f.Add(uint64(0))
|
|
f.Add(uint64(255))
|
|
f.Add(uint64(256))
|
|
f.Add(uint64(1 << 63))
|
|
f.Fuzz(func(t *testing.T, n uint64) {
|
|
var u uint64
|
|
if err := Decode(n, &u); err != nil || u != n {
|
|
t.Fatalf("uint64 changed: %d -> %d (%v)", n, u, err)
|
|
}
|
|
var i int64
|
|
err := Decode(n, &i)
|
|
if (err == nil) != (n <= math.MaxInt64) {
|
|
t.Fatalf("signed boundary: %d %v", n, err)
|
|
}
|
|
if err == nil && uint64(i) != n {
|
|
t.Fatal("signed conversion changed value")
|
|
}
|
|
var b uint8
|
|
err = Decode(n, &b)
|
|
if (err == nil) != (n <= math.MaxUint8) || err == nil && uint64(b) != n {
|
|
t.Fatalf("narrow conversion changed value: %d -> %d (%v)", n, b, err)
|
|
}
|
|
})
|
|
}
|