Repository: zeromicro/go-zero
Pull request #2730 (2022-12-28 14:25:17)

fix: key like TLSConfig not working


Patch:
diff --git a/core/conf/config.go b/core/conf/config.go
index bdaf7061..08e7f90f 100644
--- a/core/conf/config.go
+++ b/core/conf/config.go
@@ -13,8 +13,6 @@ import (
 	"github.com/zeromicro/go-zero/internal/encoding"
 )
 
-const distanceBetweenUpperAndLower = 32
-
 var loaders = map[string]func([]byte, interface{}) error{
 	".json": LoadFromJsonBytes,
 	".toml": LoadFromTomlBytes,
@@ -66,9 +64,9 @@ func LoadFromJsonBytes(content []byte, v interface{}) error {
 	}
 
 	finfo := buildFieldsInfo(reflect.TypeOf(v))
-	camelCaseKeyMap := toCamelCaseKeyMap(m, finfo)
+	lowerCaseKeyMap := toLowerCaseKeyMap(m, finfo)
 
-	return mapping.UnmarshalJsonMap(camelCaseKeyMap, v, mapping.WithCanonicalKeyFunc(toCamelCase))
+	return mapping.UnmarshalJsonMap(lowerCaseKeyMap, v, mapping.WithCanonicalKeyFunc(toLowerCase))
 }
 
 // LoadConfigFromJsonBytes loads config into v from content json bytes.
@@ -129,7 +127,7 @@ func buildStructFieldsInfo(tp reflect.Type) map[string]fieldInfo {
 	for i := 0; i < tp.NumField(); i++ {
 		field := tp.Field(i)
 		name := field.Name
-		ccName := toCamelCase(name)
+		lowerCaseName := toLowerCase(name)
 		ft := mapping.Deref(field.Type)
 
 		// flatten anonymous fields
@@ -140,7 +138,7 @@ func buildStructFieldsInfo(tp reflect.Type) map[string]fieldInfo {
 					info[k] = v
 				}
 			} else {
-				info[ccName] = fieldInfo{
+				info[lowerCaseName] = fieldInfo{
 					name: name,
 					kind: ft.Kind(),
 				}
@@ -158,7 +156,7 @@ func buildStructFieldsInfo(tp reflect.Type) map[string]fieldInfo {
 			fields = buildFieldsInfo(ft.Elem())
 		}
 
-		info[ccName] = fieldInfo{
+		info[lowerCaseName] = fieldInfo{
 			name:     name,
 			kind:     ft.Kind(),
 			children: fields,
@@ -168,58 +166,18 @@ func buildStructFieldsInfo(tp reflect.Type) map[string]fieldInfo {
 	return info
 }
 
-func toCamelCase(s string) string {
-	var buf strings.Builder
-	buf.Grow(len(s))
-	var capNext bool
-	boundary := true
-	for _, v := range s {
-		isCap := v >= 'A' && v <= 'Z'
-		isLow := v >= 'a' && v <= 'z'
-		if boundary && (isCap || isLow) {
-			if capNext {
-				if isLow {
-					v -= distanceBetweenUpperAndLower
-				}
-			} else {
-				if isCap {
-					v += distanceBetweenUpperAndLower
-				}
-			}
-			boundary = false
-		}
-		if isCap || isLow {
-			buf.WriteRune(v)
-			capNext = false
-			continue
-		}
-
-		switch v {
-		// '.' is used for chained keys, e.g. "grand.parent.child"
-		case ' ', '.', '\t':
-			buf.WriteRune(v)
-			capNext = false
-			boundary = true
-		case '_':
-			capNext = true
-			boundary = true
-		default:
-			buf.WriteRune(v)
-			capNext = true
-		}
-	}
-
-	return buf.String()
+func toLowerCase(s string) string {
+	return strings.ToLower(s)
 }
 
-func toCamelCaseInterface(v interface{}, info map[string]fieldInfo) interface{} {
+func toLowerCaseInterface(v interface{}, info map[string]fieldInfo) interface{} {
 	switch vv := v.(type) {
 	case map[string]interface{}:
-		return toCamelCaseKeyMap(vv, info)
+		return toLowerCaseKeyMap(vv, info)
 	case []interface{}:
 		var arr []interface{}
 		for _, vvv := range vv {
-			arr = append(arr, toCamelCaseInterface(vvv, info))
+			arr = append(arr, toLowerCaseInterface(vvv, info))
 		}
 		return arr
 	default:
@@ -227,19 +185,19 @@ func toCamelCaseInterface(v interface{}, info map[string]fieldInfo) interface{}
 	}
 }
 
-func toCamelCaseKeyMap(m map[string]interface{}, info map[string]fieldInfo) map[string]interface{} {
+func toLowerCaseKeyMap(m map[string]interface{}, info map[string]fieldInfo) map[string]interface{} {
 	res := make(map[string]interface{})
 
 	for k, v := range m {
 		ti, ok := info[k]
 		if ok {
-			res[k] = toCamelCaseInterface(v, ti.children)
+			res[k] = toLowerCaseInterface(v, ti.children)
 			continue
 		}
 
-		cck := toCamelCase(k)
-		if ti, ok = info[cck]; ok {
-			res[toCamelCase(k)] = toCamelCaseInterface(v, ti.children)
+		lk := toLowerCase(k)
+		if ti, ok = info[lk]; ok {
+			res[lk] = toLowerCaseInterface(v, ti.children)
 		} else {
 			res[k] = v
 		}


Test patch:
diff --git a/core/conf/config_test.go b/core/conf/config_test.go
index 547b4745..82dc5545 100644
--- a/core/conf/config_test.go
+++ b/core/conf/config_test.go
@@ -237,23 +237,23 @@ func TestToCamelCase(t *testing.T) {
 		},
 		{
 			input:  "hello_world",
-			expect: "helloWorld",
+			expect: "hello_world",
 		},
 		{
 			input:  "Hello_world",
-			expect: "helloWorld",
+			expect: "hello_world",
 		},
 		{
 			input:  "hello_World",
-			expect: "helloWorld",
+			expect: "hello_world",
 		},
 		{
 			input:  "helloWorld",
-			expect: "helloWorld",
+			expect: "helloworld",
 		},
 		{
 			input:  "HelloWorld",
-			expect: "helloWorld",
+			expect: "helloworld",
 		},
 		{
 			input:  "hello World",
@@ -269,34 +269,34 @@ func TestToCamelCase(t *testing.T) {
 		},
 		{
 			input:  "Hello World foo_bar",
-			expect: "hello world fooBar",
+			expect: "hello world foo_bar",
 		},
 		{
 			input:  "Hello World foo_Bar",
-			expect: "hello world fooBar",
+			expect: "hello world foo_bar",
 		},
 		{
 			input:  "Hello World Foo_bar",
-			expect: "hello world fooBar",
+			expect: "hello world foo_bar",
 		},
 		{
 			input:  "Hello World Foo_Bar",
-			expect: "hello world fooBar",
+			expect: "hello world foo_bar",
 		},
 		{
 			input:  "Hello.World Foo_Bar",
-			expect: "hello.world fooBar",
+			expect: "hello.world foo_bar",
 		},
 		{
 			input:  "你好 World Foo_Bar",
-			expect: "你好 world fooBar",
+			expect: "你好 world foo_bar",
 		},
 	}
 
 	for _, test := range tests {
 		test := test
 		t.Run(test.input, func(t *testing.T) {
-			assert.Equal(t, test.expect, toCamelCase(test.input))
+			assert.Equal(t, test.expect, toLowerCase(test.input))
 		})
 	}
 }
@@ -332,6 +332,22 @@ func TestLoadFromYamlBytes(t *testing.T) {
 	assert.Equal(t, "foo", val.Layer1.Layer2.Layer3)
 }
 
+func TestLoadFromYamlBytesTerm(t *testing.T) {
+	input := []byte(`layer1:
+  layer2:
+    tls_conf: foo`)
+	var val struct {
+		Layer1 struct {
+			Layer2 struct {
+				Layer3 string `json:"tls_conf"`
+			}
+		}
+	}
+
+	assert.NoError(t, LoadFromYamlBytes(input, &val))
+	assert.Equal(t, "foo", val.Layer1.Layer2.Layer3)
+}
+
 func TestLoadFromYamlBytesLayers(t *testing.T) {
 	input := []byte(`layer1:
   layer2: