fix(decode): allocate embedded pointer maps and settle case collisions
Assisted-by: GLM 5.3
This commit is contained in:
@@ -1690,3 +1690,85 @@ func TestErrorMessagesGolden(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestLocalTimeLocationLeavesOffsetsAlone pins that the option's zone is
|
||||
// used for local date-times only: an offset date-time keeps the offset the
|
||||
// document wrote.
|
||||
func TestLocalTimeLocationLeavesOffsetsAlone(t *testing.T) {
|
||||
var cfg struct {
|
||||
Stamp time.Time `toml:"stamp"`
|
||||
}
|
||||
err := Unmarshal([]byte("stamp = 1979-05-27T07:32:00-07:00\n"), &cfg,
|
||||
LocalTimeLocation(time.FixedZone("Prague", 2*60*60)))
|
||||
if err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if _, off := cfg.Stamp.Zone(); off != -7*60*60 {
|
||||
t.Errorf("offset = %d, want the document's -07:00", off/3600)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnmarshalCaseCollisionIsDeterministic pins that two keys differing
|
||||
// only in case, both matching one field, resolve the same way on every run
|
||||
// and on both decode paths.
|
||||
func TestUnmarshalCaseCollisionIsDeterministic(t *testing.T) {
|
||||
type cfg struct {
|
||||
Host string `toml:"host"`
|
||||
}
|
||||
in := []byte("Host = \"upper\"\nhost = \"lower\"\n")
|
||||
// The tree path iterates a map, so pin the winner across many runs.
|
||||
var want string
|
||||
for range 50 {
|
||||
var viaTree cfg
|
||||
if err := treeDecodeInto(in, &viaTree); err != nil {
|
||||
t.Fatalf("tree decode: %v", err)
|
||||
}
|
||||
if want == "" {
|
||||
want = viaTree.Host
|
||||
} else if viaTree.Host != want {
|
||||
t.Fatalf("tree decode is not deterministic: %q then %q", want, viaTree.Host)
|
||||
}
|
||||
}
|
||||
var targeted cfg
|
||||
if err := Unmarshal(in, &targeted); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if targeted.Host != want {
|
||||
t.Errorf("targeted Host = %q, tree %q", targeted.Host, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnmarshalEmbeddedPointerMap pins that leftover keys reach an embedded
|
||||
// pointer to a map, allocating it, rather than panicking on the pointer.
|
||||
func TestUnmarshalEmbeddedPointerMap(t *testing.T) {
|
||||
type Extra map[string]int
|
||||
type cfg struct {
|
||||
*Extra
|
||||
Name string `toml:"name"`
|
||||
}
|
||||
var c cfg
|
||||
err := Unmarshal([]byte("name = \"x\"\nrogue = 7\n"), &c)
|
||||
if err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if c.Extra == nil || (*c.Extra)["rogue"] != 7 {
|
||||
t.Errorf("embedded map = %v, want rogue allocated and filled", c.Extra)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnmarshalIgnoresEncodeTagOptions pins that the emission-only tag
|
||||
// options change nothing on the decode side.
|
||||
func TestUnmarshalIgnoresEncodeTagOptions(t *testing.T) {
|
||||
type cfg struct {
|
||||
Name string `toml:"name,omitempty"`
|
||||
Port int `toml:"port,omitzero,comment=The port"`
|
||||
}
|
||||
var c cfg
|
||||
err := Unmarshal([]byte("name = \"x\"\nport = 8080\n"), &c)
|
||||
if err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if c.Name != "x" || c.Port != 8080 {
|
||||
t.Errorf("cfg = %+v, want both fields filled", c)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user