test: add FuzzMarshal, golden messages, synctest cancellation and cross smoke
Test / test (push) Successful in 1m31s
Test / test (push) Successful in 1m31s
Assisted-by: GLM 5.3 Flash
This commit is contained in:
+120
@@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -1574,3 +1575,122 @@ func TestCancelInsideValue(t *testing.T) {
|
||||
t.Errorf("err = %v, want context.Canceled", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancellationSynctest(t *testing.T) {
|
||||
// The bubble makes the cost of the immediate-cancellation path visible in
|
||||
// virtual microseconds, and synctest.Wait holds the test to leaving no
|
||||
// goroutine behind.
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
start := time.Now()
|
||||
var tree map[string]any
|
||||
err := NewDecoder().DecodeContext(ctx, []byte("a = 1\n"), &tree)
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Errorf("err = %v, want context.Canceled", err)
|
||||
}
|
||||
if d := time.Since(start); d != 0 {
|
||||
t.Errorf("the parse consumed %v of virtual time, want none", d)
|
||||
}
|
||||
synctest.Wait()
|
||||
})
|
||||
}
|
||||
|
||||
func TestErrorMessagesGolden(t *testing.T) {
|
||||
// The exact texts the library promises, pinned against unintended edits.
|
||||
type Config struct {
|
||||
Weight uint8 `toml:"weight"`
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
read func() error
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "missing equals",
|
||||
read: func() error { _, err := ParseMap([]byte("a 1\n")); return err },
|
||||
want: "interpres: line 1: expected '=' after key",
|
||||
},
|
||||
{
|
||||
name: "duplicate key",
|
||||
read: func() error { _, err := ParseMap([]byte("a = 1\na = 2\n")); return err },
|
||||
want: `interpres: line 2: duplicate key "a"`,
|
||||
},
|
||||
{
|
||||
name: "unterminated string",
|
||||
read: func() error { _, err := ParseMap([]byte("a = \"open\n")); return err },
|
||||
want: "interpres: line 1: unterminated string",
|
||||
},
|
||||
{
|
||||
name: "leading zero",
|
||||
read: func() error { _, err := ParseMap([]byte("a = 01\n")); return err },
|
||||
want: "interpres: line 1: leading zeros are not allowed in numbers",
|
||||
},
|
||||
{
|
||||
name: "bad escape",
|
||||
read: func() error { _, err := ParseMap([]byte(`a = "\q"` + "\n")); return err },
|
||||
want: `interpres: line 1: invalid escape sequence \q`,
|
||||
},
|
||||
{
|
||||
name: "nesting limit",
|
||||
read: func() error {
|
||||
var b strings.Builder
|
||||
b.WriteString("a = ")
|
||||
for range 11 {
|
||||
b.WriteString("[")
|
||||
}
|
||||
for range 11 {
|
||||
b.WriteString("]")
|
||||
}
|
||||
b.WriteString("\n")
|
||||
var tree map[string]any
|
||||
err := NewDecoder().MaxDepth(10).Decode([]byte(b.String()), &tree)
|
||||
return err
|
||||
},
|
||||
want: "interpres: line 1: nesting exceeds the limit of 10",
|
||||
},
|
||||
{
|
||||
name: "decode overflow",
|
||||
read: func() error {
|
||||
var cfg Config
|
||||
return Unmarshal([]byte("weight = 300\n"), &cfg)
|
||||
},
|
||||
want: "interpres: weight: integer 300 overflows uint8",
|
||||
},
|
||||
{
|
||||
name: "unknown field",
|
||||
read: func() error {
|
||||
var cfg struct {
|
||||
Known int `toml:"known"`
|
||||
}
|
||||
return NewDecoder().DisallowUnknownFields().Decode([]byte("mystery = 1\n"), &cfg)
|
||||
},
|
||||
want: `interpres: unknown field "mystery" for struct { Known int "toml:\"known\"" }`,
|
||||
},
|
||||
{
|
||||
name: "decode target",
|
||||
read: func() error { return Unmarshal([]byte("a = 1\n"), Config{}) },
|
||||
want: "interpres: decode target must be a non-nil pointer",
|
||||
},
|
||||
{
|
||||
name: "encode nil pointer",
|
||||
read: func() error {
|
||||
var p *Config
|
||||
_, err := Marshal(p)
|
||||
return err
|
||||
},
|
||||
want: "interpres: cannot marshal nil pointer",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.read()
|
||||
if err == nil {
|
||||
t.Fatalf("no error, want %q", tt.want)
|
||||
}
|
||||
if err.Error() != tt.want {
|
||||
t.Errorf("message = %q, want %q", err.Error(), tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user