Files
toml/audit_fix_test.go
T
2026-07-13 02:45:49 -04:00

201 lines
5.3 KiB
Go

package toml
import (
"math"
"strings"
"testing"
)
func TestDecode_NumericOverflow(t *testing.T) {
type T struct {
I8 int8 `toml:"i8"`
U8 uint8 `toml:"u8"`
F32 float32 `toml:"f32"`
}
var tgt T
if err := Decode(map[string]any{"i8": 300}, &tgt); err == nil {
t.Errorf("300 into int8 must error, got %d", tgt.I8)
}
if err := Decode(map[string]any{"u8": 256}, &tgt); err == nil {
t.Errorf("256 into uint8 must error, got %d", tgt.U8)
}
if err := Decode(map[string]any{"f32": 1e300}, &tgt); err == nil {
t.Errorf("1e300 into float32 must error, got %g", tgt.F32)
}
// Boundaries remain valid
if err := Decode(map[string]any{"i8": 127, "u8": 255}, &tgt); err != nil {
t.Fatalf("boundary decode failed: %v", err)
}
if tgt.I8 != 127 || tgt.U8 != 255 {
t.Errorf("boundary values: %d %d", tgt.I8, tgt.U8)
}
}
func TestDecode_UnsupportedKinds(t *testing.T) {
type T struct {
C complex128 `toml:"v"`
}
var c T
if err := Decode(map[string]any{"v": 1}, &c); err == nil {
t.Error("complex128 target must error, not zero-fill")
}
type T2 struct {
Ch chan int `toml:"v"`
}
var c2 T2
if err := Decode(map[string]any{"v": 1}, &c2); err == nil {
t.Error("chan target must error")
}
}
func TestDecode_NonEmptyInterface(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("input-triggered panic: %v", r)
}
}()
type T struct {
R interface{ Read([]byte) (int, error) } `toml:"r"`
}
var tgt T
if err := Decode(map[string]any{"r": map[string]any{}}, &tgt); err == nil {
t.Error("map into non-empty interface must error")
}
}
func TestDecode_Uint64Wrap(t *testing.T) {
type T struct {
V int64 `toml:"v"`
}
var tgt T
if err := Decode(map[string]any{"v": uint64(math.MaxUint64)}, &tgt); err == nil {
t.Errorf("MaxUint64 into int64 must error, got %d", tgt.V)
}
if err := Decode(map[string]any{"v": uint(math.MaxUint64)}, &tgt); err == nil {
t.Errorf("uint wrap into int64 must error, got %d", tgt.V)
}
if err := Decode(map[string]any{"v": uint64(42)}, &tgt); err != nil || tgt.V != 42 {
t.Errorf("in-range uint64 failed: %v %d", err, tgt.V)
}
}
func TestMarshal_FloatFormatting(t *testing.T) {
b, err := Marshal(map[string]any{"f": float32(3.14)})
if err != nil {
t.Fatal(err)
}
if got := strings.TrimSpace(string(b)); got != "f = 3.14" {
t.Errorf("float32 noise digits: %s", got)
}
b, err = Marshal(map[string]any{"f": 1e100})
if err != nil {
t.Fatal(err)
}
if got := strings.TrimSpace(string(b)); got != "f = 1e+100" {
t.Errorf("digit expansion instead of exponent: %s", got)
}
var m map[string]any
if err := Unmarshal(b, &m); err != nil {
t.Fatalf("re-parse of exponent form failed: %v", err)
}
if m["f"] != 1e100 {
t.Errorf("round trip mismatch: %v", m["f"])
}
// Integral floats keep the .0 fixup
b, _ = Marshal(map[string]any{"f": 100.0})
if got := strings.TrimSpace(string(b)); got != "f = 100.0" {
t.Errorf(".0 fixup lost: %s", got)
}
}
func TestMarshal_NaNInf(t *testing.T) {
for _, v := range []float64{math.NaN(), math.Inf(1), math.Inf(-1)} {
if _, err := Marshal(map[string]any{"f": v}); err == nil {
t.Errorf("%v must fail to encode", v)
}
}
}
func TestMarshal_SliceHomogeneity(t *testing.T) {
if _, err := Marshal(map[string]any{"x": []any{map[string]any{"a": 1}, 2}}); err == nil {
t.Error("mixed table/scalar slice must error")
}
if _, err := Marshal(map[string]any{"x": []any{1, nil, 2}}); err == nil {
t.Error("nil interface element must error")
}
type Item struct {
N int `toml:"n"`
}
b, err := Marshal(map[string]any{"items": []*Item{nil, {N: 1}}})
if err != nil {
t.Fatalf("nil pointer in table slice must be skipped, not error: %v", err)
}
if strings.Count(string(b), "[[items]]") != 1 {
t.Errorf("expected exactly one [[items]]:\n%s", b)
}
}
func TestMarshal_TagSortedKeys(t *testing.T) {
type T struct {
B int `toml:"z"`
Z int `toml:"a"`
}
b, err := Marshal(T{B: 1, Z: 2})
if err != nil {
t.Fatal(err)
}
if got := strings.TrimSpace(string(b)); got != "a = 2\nz = 1" {
t.Errorf("keys not sorted by emitted name:\n%s", got)
}
}
func TestLexer_UnicodeEscapes(t *testing.T) {
var m map[string]any
if err := Unmarshal([]byte(`s = "caf\u00E9 \U0001F600"`), &m); err != nil {
t.Fatalf("unicode escape parse failed: %v", err)
}
if m["s"] != "café 😀" {
t.Errorf("got %q", m["s"])
}
for _, in := range []string{
`s = "\uD800"`, // surrogate
`s = "\u12"`, // too few digits
`s = "\U00110000"`, // > MaxRune
`s = "\uZZZZ"`, // non-hex
} {
if err := Unmarshal([]byte(in), &m); err == nil {
t.Errorf("%s should fail", in)
}
}
}
func TestParser_InlineTableImmutable(t *testing.T) {
for _, in := range []string{
"t = { a = 1 }\nt.b = 2",
"t = { a = 1 }\n[t]\nb = 2",
"t = { a = 1 }\n[t.sub]\nb = 2",
} {
p := NewParser([]byte(in))
if _, err := p.Parse(); err == nil {
t.Errorf("inline table extension should fail:\n%s", in)
}
}
// Intra-table dotted keys remain valid
var m map[string]any
if err := Unmarshal([]byte(`t = { a.b = 1, a.c = 2 }`), &m); err != nil {
t.Errorf("dotted keys within inline table must parse: %v", err)
}
}
func TestParser_ValueDepthLimit(t *testing.T) {
input := "x = " + strings.Repeat("[", 5000) + strings.Repeat("]", 5000)
p := NewParser([]byte(input))
if _, err := p.Parse(); err == nil {
t.Error("expected nesting depth error")
}
}