Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -1423,3 +1423,57 @@ func (b *ctxBoth) UnmarshalTOML(data any) error {
|
|||||||
b.plainCalled = true
|
b.plainCalled = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEmbeddedMapRule(t *testing.T) {
|
||||||
|
t.Run("only the first embedded map takes the leftover keys", func(t *testing.T) {
|
||||||
|
type ExtraMap map[string]any
|
||||||
|
type MoreMap map[string]any
|
||||||
|
type Config struct {
|
||||||
|
Port int
|
||||||
|
ExtraMap
|
||||||
|
MoreMap
|
||||||
|
}
|
||||||
|
var cfg Config
|
||||||
|
in := []byte("port = 8080\nlang = \"cs\"\nregion = \"EU\"\n")
|
||||||
|
if err := Unmarshal(in, &cfg); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if cfg.Port != 8080 {
|
||||||
|
t.Errorf("port = %d", cfg.Port)
|
||||||
|
}
|
||||||
|
if cfg.ExtraMap["lang"] != "cs" || cfg.ExtraMap["region"] != "EU" {
|
||||||
|
t.Errorf("extra = %v, want the leftover keys", cfg.ExtraMap)
|
||||||
|
}
|
||||||
|
if len(cfg.MoreMap) != 0 {
|
||||||
|
t.Errorf("more = %v, want empty: only the first embedded map is the filler", cfg.MoreMap)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("a tagged embedded map is an ordinary field", func(t *testing.T) {
|
||||||
|
type Config struct {
|
||||||
|
Extra map[string]any `toml:"extra"`
|
||||||
|
}
|
||||||
|
var cfg Config
|
||||||
|
if err := Unmarshal([]byte("extra = {a = 1}\n"), &cfg); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if cfg.Extra["a"] != int64(1) {
|
||||||
|
t.Errorf("extra = %v", cfg.Extra)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeMergesIntoNonEmptyMap(t *testing.T) {
|
||||||
|
dst := map[string]any{"keep": "me", "port": 1}
|
||||||
|
if err := Unmarshal([]byte("port = 8080\nlang = \"cs\"\n"), &dst); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if dst["keep"] != "me" {
|
||||||
|
t.Errorf("keep = %v, want the pre-existing key kept", dst["keep"])
|
||||||
|
}
|
||||||
|
if dst["port"] != int64(8080) {
|
||||||
|
t.Errorf("port = %v, want the document's value to win", dst["port"])
|
||||||
|
}
|
||||||
|
if dst["lang"] != "cs" {
|
||||||
|
t.Errorf("lang = %v, want the key added", dst["lang"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+5
-2
@@ -202,7 +202,8 @@ table with `Number`, which keeps the literal; see
|
|||||||
|
|
||||||
- `*struct`, matched per the field rules below
|
- `*struct`, matched per the field rules below
|
||||||
- `*map[string]any` or `*map[string]T`, keys become map keys and values decode
|
- `*map[string]any` or `*map[string]T`, keys become map keys and values decode
|
||||||
into `T` recursively
|
into `T` recursively; a map that already holds entries is merged into, the
|
||||||
|
document's values replacing same-named keys and the rest left standing
|
||||||
- `*OrderedMap`, the keys fill in the order the document wrote them; see
|
- `*OrderedMap`, the keys fill in the order the document wrote them; see
|
||||||
[Ordered tables](#ordered-tables)
|
[Ordered tables](#ordered-tables)
|
||||||
- `*any`, receives the whole parsed tree unchanged
|
- `*any`, receives the whole parsed tree unchanged
|
||||||
@@ -220,7 +221,9 @@ For a struct destination, a TOML key matches a field as follows:
|
|||||||
into the embedded struct and matches its own fields against the same keys,
|
into the embedded struct and matches its own fields against the same keys,
|
||||||
mirroring how the encoder flattens it. A nil embedded pointer struct is
|
mirroring how the encoder flattens it. A nil embedded pointer struct is
|
||||||
allocated on demand. An untagged embedded map receives the keys no field
|
allocated on demand. An untagged embedded map receives the keys no field
|
||||||
claims.
|
claims; when a struct embeds several untagged maps, the first one
|
||||||
|
declared takes all of them and the rest stay untouched, so the rule stays
|
||||||
|
predictable.
|
||||||
4. The key itself is lower-cased before lookup, so the match is
|
4. The key itself is lower-cased before lookup, so the match is
|
||||||
case-insensitive on both sides: `DATABASEURL` matches a field named
|
case-insensitive on both sides: `DATABASEURL` matches a field named
|
||||||
`DatabaseUrl`.
|
`DatabaseUrl`.
|
||||||
|
|||||||
Reference in New Issue
Block a user