Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,18 @@ func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bo
// mapToField maps the given value to the matching field of the given section.
// The sectionIndex is the index (if non unique sections are enabled) to which the value should be added.
func (s *Section) mapToField(val reflect.Value, isStrict bool, sectionIndex int, sectionName string) error {
if val.Kind() == reflect.Pointer {
for val.Kind() == reflect.Pointer {
if val.IsNil() {
if !val.CanSet() {
return fmt.Errorf("cannot initialize nil pointer: value is not settable")
}
val.Set(reflect.New(val.Type().Elem()))
}
val = val.Elem()
}
if !val.IsValid() {
return fmt.Errorf("cannot map to invalid value")
}
typ := val.Type()

for i := 0; i < typ.NumField(); i++ {
Expand Down
44 changes: 44 additions & 0 deletions struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,50 @@ names=alice, bruce`))
})
}

// Regression test for https://github.com/go-ini/ini/issues/370:
// Mapping non-unique sections into a slice of struct pointers ([]*T) must
// not panic.
func Test_MapToSliceOfStructPointers(t *testing.T) {
const data = `[Peer]
PublicKey = key1
[Peer]
PublicKey = key2
`
type Peer struct {
PublicKey string `ini:"PublicKey"`
}
type Config struct {
Peers []*Peer `ini:"Peer,nonunique"`
}
f, err := LoadSources(LoadOptions{AllowNonUniqueSections: true}, []byte(data))
assert.NoError(t, err)
cfg := new(Config)
assert.NoError(t, f.MapTo(cfg))
assert.Len(t, cfg.Peers, 2)
if len(cfg.Peers) == 2 {
assert.Equal(t, "key1", cfg.Peers[0].PublicKey)
assert.Equal(t, "key2", cfg.Peers[1].PublicKey)
}
}

// Regression test for https://github.com/go-ini/ini/issues/369 and #370:
// MapTo with a nil struct pointer must not panic; it should auto-initialize
// the pointer (analogous to encoding/json behaviour) and populate the struct.
func Test_MapToNilPointer(t *testing.T) {
f, err := Load([]byte("user = alice\npass = secret\n"))
assert.NoError(t, err)

type S struct {
User string `ini:"user"`
Pass string `ini:"pass"`
}
var s *S
assert.NoError(t, f.MapTo(&s), "MapTo with nil pointer should not return an error")
assert.NotNil(t, s, "nil pointer should have been initialized by MapTo")
assert.Equal(t, "alice", s.User)
assert.Equal(t, "secret", s.Pass)
}

func Test_MapToStructNonUniqueSections(t *testing.T) {
t.Run("map to struct non unique", func(t *testing.T) {
t.Run("map file to struct non unique", func(t *testing.T) {
Expand Down