Repository: zeromicro/go-zero
Pull request #3059 (2023-03-23 14:18:37)

fix: #3058

codecov[bot]: ## [Codecov](https://codecov.io/gh/zeromicro/go-zero/pull/3059?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#3059](https://codecov.io/gh/zeromicro/go-zero/pull/3059?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (75311c4) into [master](https://codecov.io/gh/zeromicro/go-zero/commit/0ab06f62ca827bfbeaabc11b17d2d5e92014092b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (0ab06f6) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.


| [Impacted Files](https://codecov.io/gh/zeromicro/go-zero/pull/3059?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [core/mapping/unmarshaler.go](https://codecov.io/gh/zeromicro/go-zero/pull/3059?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-Y29yZS9tYXBwaW5nL3VubWFyc2hhbGVyLmdv) | `89.25% <100.00%> (+0.02%)` | :arrow_up: |


Patch:
diff --git a/core/mapping/unmarshaler.go b/core/mapping/unmarshaler.go
index d19469f3..e64a7675 100644
--- a/core/mapping/unmarshaler.go
+++ b/core/mapping/unmarshaler.go
@@ -695,6 +695,10 @@ func (u *Unmarshaler) processFieldWithEnvValue(fieldType reflect.Type, value ref
 
 func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect.Value,
 	m valuerWithParent, fullName string) error {
+	if !field.IsExported() {
+		return nil
+	}
+
 	key, opts, err := u.parseOptionsWithContext(field, m, fullName)
 	if err != nil {
 		return err
@@ -869,12 +873,9 @@ func (u *Unmarshaler) unmarshalWithFullName(m valuerWithParent, v any, fullName
 
 	numFields := baseType.NumField()
 	for i := 0; i < numFields; i++ {
-		field := baseType.Field(i)
-		if !field.IsExported() {
-			continue
-		}
-
-		if err := u.processField(field, valElem.Field(i), m, fullName); err != nil {
+		typeField := baseType.Field(i)
+		valueField := valElem.Field(i)
+		if err := u.processField(typeField, valueField, m, fullName); err != nil {
 			return err
 		}
 	}


Test patch:
diff --git a/core/conf/config_test.go b/core/conf/config_test.go
index 72392511..a0d15140 100644
--- a/core/conf/config_test.go
+++ b/core/conf/config_test.go
@@ -123,6 +123,24 @@ d = "abcd"
 	}
 }
 
+func TestConfigWithLower(t *testing.T) {
+	text := `a = "foo"
+b = 1
+`
+	tmpfile, err := createTempFile(".toml", text)
+	assert.Nil(t, err)
+	defer os.Remove(tmpfile)
+
+	var val struct {
+		A string `json:"a"`
+		b int
+	}
+	if assert.NoError(t, Load(tmpfile, &val)) {
+		assert.Equal(t, "foo", val.A)
+		assert.Equal(t, 0, val.b)
+	}
+}
+
 func TestConfigJsonCanonical(t *testing.T) {
 	text := []byte(`{"a": "foo", "B": "bar"}`)
 
diff --git a/core/mapping/unmarshaler_test.go b/core/mapping/unmarshaler_test.go
index 4b6148a2..1f723263 100644
--- a/core/mapping/unmarshaler_test.go
+++ b/core/mapping/unmarshaler_test.go
@@ -53,6 +53,52 @@ func TestUnmarshalWithoutTagName(t *testing.T) {
 	}
 }
 
+func TestUnmarshalWithLowerField(t *testing.T) {
+	type (
+		Lower struct {
+			value int `key:"lower"`
+		}
+
+		inner struct {
+			Lower
+			Optional bool `key:",optional"`
+		}
+	)
+	m := map[string]any{
+		"Optional": true,
+		"lower":    1,
+	}
+
+	var in inner
+	if assert.NoError(t, UnmarshalKey(m, &in)) {
+		assert.True(t, in.Optional)
+		assert.Equal(t, 0, in.value)
+	}
+}
+
+func TestUnmarshalWithLowerAnonymousStruct(t *testing.T) {
+	type (
+		lower struct {
+			Value int `key:"lower"`
+		}
+
+		inner struct {
+			lower
+			Optional bool `key:",optional"`
+		}
+	)
+	m := map[string]any{
+		"Optional": true,
+		"lower":    1,
+	}
+
+	var in inner
+	if assert.NoError(t, UnmarshalKey(m, &in)) {
+		assert.True(t, in.Optional)
+		assert.Equal(t, 1, in.Value)
+	}
+}
+
 func TestUnmarshalWithoutTagNameWithCanonicalKey(t *testing.T) {
 	type inner struct {
 		Name string `key:"name"`