struct: correctly mapping non unique sections to slice field (#242)

* bugfix: use the value from the correct section when using non unique sections in some special cases

* refactor wording and small fix
This commit is contained in:
aligator
2020-05-28 13:00:39 +08:00
committed by GitHub
parent ad8a10643d
commit 1fc6efb6f2
2 changed files with 55 additions and 6 deletions
+11 -6
View File
@@ -278,7 +278,9 @@ func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bo
return rawName, omitEmpty, allowShadow, allowNonUnique
}
func (s *Section) mapToField(val reflect.Value, isStrict bool) error {
// 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) error {
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
@@ -307,13 +309,16 @@ func (s *Section) mapToField(val reflect.Value, isStrict bool) error {
}
if isAnonymous || isStruct || isStructPtr {
if sec, err := s.f.GetSection(fieldName); err == nil {
if secs, err := s.f.SectionsByName(fieldName); err == nil {
if len(secs) <= sectionIndex {
return fmt.Errorf("there are not enough sections (%d <= %d) for the field %q", len(secs), sectionIndex, fieldName)
}
// Only set the field to non-nil struct value if we have a section for it.
// Otherwise, we end up with a non-nil struct ptr even though there is no data.
if isStructPtr && field.IsNil() {
field.Set(reflect.New(tpField.Type.Elem()))
}
if err = sec.mapToField(field, isStrict); err != nil {
if err = secs[sectionIndex].mapToField(field, isStrict, sectionIndex); err != nil {
return fmt.Errorf("map to field %q: %v", fieldName, err)
}
continue
@@ -350,9 +355,9 @@ func (s *Section) mapToSlice(secName string, val reflect.Value, isStrict bool) (
}
typ := val.Type().Elem()
for _, sec := range secs {
for i, sec := range secs {
elem := reflect.New(typ)
if err = sec.mapToField(elem, isStrict); err != nil {
if err = sec.mapToField(elem, isStrict, i); err != nil {
return reflect.Value{}, fmt.Errorf("map to field from section %q: %v", secName, err)
}
@@ -382,7 +387,7 @@ func (s *Section) mapTo(v interface{}, isStrict bool) error {
return nil
}
return s.mapToField(val, isStrict)
return s.mapToField(val, isStrict, 0)
}
// MapTo maps section to given struct.
+44
View File
@@ -414,6 +414,50 @@ func Test_MapToStructNonUniqueSections(t *testing.T) {
So(newPeerSlice[1].AllowedIPs[0], ShouldEqual, "10.2.0.3/32")
So(newPeerSlice[1].AllowedIPs[1], ShouldEqual, "fd00:2::3/128")
})
Convey("Map non unique sections with subsections to struct", func() {
iniFile, err := ini.LoadSources(ini.LoadOptions{AllowNonUniqueSections: true}, strings.NewReader(`
[Section]
FieldInSubSection = 1
FieldInSubSection2 = 2
FieldInSection = 3
[Section]
FieldInSubSection = 4
FieldInSubSection2 = 5
FieldInSection = 6
`))
So(err, ShouldBeNil)
type SubSection struct {
FieldInSubSection string `ini:"FieldInSubSection"`
}
type SubSection2 struct {
FieldInSubSection2 string `ini:"FieldInSubSection2"`
}
type Section struct {
SubSection `ini:"Section"`
SubSection2 `ini:"Section"`
FieldInSection string `ini:"FieldInSection"`
}
type File struct {
Sections []Section `ini:"Section,,,nonunique"`
}
f := new(File)
err = iniFile.MapTo(f)
So(err, ShouldBeNil)
So(f.Sections[0].FieldInSubSection, ShouldEqual, "1")
So(f.Sections[0].FieldInSubSection2, ShouldEqual, "2")
So(f.Sections[0].FieldInSection, ShouldEqual, "3")
So(f.Sections[1].FieldInSubSection, ShouldEqual, "4")
So(f.Sections[1].FieldInSubSection2, ShouldEqual, "5")
So(f.Sections[1].FieldInSection, ShouldEqual, "6")
})
})
}