From fee1b34973345b065c8925b04f3bfcdde98f3071 Mon Sep 17 00:00:00 2001
From: Kagaya <kagaya85@outlook.com>
Date: Thu, 26 Aug 2021 14:34:35 +0800
Subject: [PATCH] test(config): add test case for resolver (#1377)

---
 config/config_test.go  | 132 ------------------------------------
 config/options.go      |   5 +-
 config/options_test.go | 148 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 149 insertions(+), 136 deletions(-)

diff --git a/config/config_test.go b/config/config_test.go
index 314335cb8..061465871 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -2,7 +2,6 @@ package config
 
 import (
 	"errors"
-	"reflect"
 	"testing"
 
 	"github.com/go-kratos/kratos/v2/log"
@@ -164,134 +163,3 @@ func TestConfig(t *testing.T) {
 	assert.Equal(t, endpoint1, testConf.Endpoints[0])
 	assert.Equal(t, 2, len(testConf.Endpoints))
 }
-
-func TestDefaultResolver(t *testing.T) {
-	var (
-		portString = "8080"
-		countInt   = 10
-		rateFloat  = 0.9
-	)
-
-	data := map[string]interface{}{
-		"foo": map[string]interface{}{
-			"bar": map[string]interface{}{
-				"notexist": "${NOTEXIST:100}",
-				"port":     "${PORT:8081}",
-				"count":    "${COUNT:0}",
-				"enable":   "${ENABLE:false}",
-				"rate":     "${RATE}",
-				"empty":    "${EMPTY:foobar}",
-				"url":      "${URL:http://example.com}",
-				"array": []interface{}{
-					"${PORT}",
-					map[string]interface{}{"foobar": "${NOTEXIST:8081}"},
-				},
-				"value1": "${test.value}",
-				"value2": "$PORT",
-				"value3": "$PORT:default",
-			},
-		},
-		"test": map[string]interface{}{
-			"value": "foobar",
-		},
-		"PORT":   "8080",
-		"COUNT":  "10",
-		"ENABLE": "true",
-		"RATE":   "0.9",
-		"EMPTY":  "",
-	}
-
-	tests := []struct {
-		name   string
-		path   string
-		expect interface{}
-	}{
-		{
-			name:   "test not exist int env with default",
-			path:   "foo.bar.notexist",
-			expect: 100,
-		},
-		{
-			name:   "test string with default",
-			path:   "foo.bar.port",
-			expect: portString,
-		},
-		{
-			name:   "test int with default",
-			path:   "foo.bar.count",
-			expect: countInt,
-		},
-		{
-			name:   "test bool with default",
-			path:   "foo.bar.enable",
-			expect: true,
-		},
-		{
-			name:   "test float without default",
-			path:   "foo.bar.rate",
-			expect: rateFloat,
-		},
-		{
-			name:   "test empty value with default",
-			path:   "foo.bar.empty",
-			expect: "",
-		},
-		{
-			name:   "test url with default",
-			path:   "foo.bar.url",
-			expect: "http://example.com",
-		},
-		{
-			name:   "test array",
-			path:   "foo.bar.array",
-			expect: []interface{}{portString, map[string]interface{}{"foobar": "8081"}},
-		},
-		{
-			name:   "test ${test.value}",
-			path:   "foo.bar.value1",
-			expect: "foobar",
-		},
-	}
-
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			err := defaultResolver(data)
-			assert.NoError(t, err)
-			rd := reader{
-				values: data,
-			}
-			if v, ok := rd.Value(test.path); ok {
-				var actual interface{}
-				switch test.expect.(type) {
-				case int:
-					if actual, err = v.Int(); err == nil {
-						assert.Equal(t, test.expect, int(actual.(int64)), "int value should be equal")
-					}
-				case string:
-					if actual, err = v.String(); err == nil {
-						assert.Equal(t, test.expect, actual, "string value should be equal")
-					}
-				case bool:
-					if actual, err = v.Bool(); err == nil {
-						assert.Equal(t, test.expect, actual, "bool value should be equal")
-					}
-				case float64:
-					if actual, err = v.Float(); err == nil {
-						assert.Equal(t, test.expect, actual, "float64 value should be equal")
-					}
-				default:
-					actual = v.Load()
-					if !reflect.DeepEqual(test.expect, actual) {
-						t.Logf("expect: %#v, actural: %#v", test.expect, actual)
-						t.Fail()
-					}
-				}
-				if err != nil {
-					t.Error(err)
-				}
-			} else {
-				t.Error("value path not found")
-			}
-		})
-	}
-}
diff --git a/config/options.go b/config/options.go
index c86dd755c..d1cbeced8 100644
--- a/config/options.go
+++ b/config/options.go
@@ -124,10 +124,7 @@ func defaultResolver(input map[string]interface{}) error {
 }
 
 func expand(s string, mapping func(string) string) string {
-	r, err := regexp.Compile(`\${(.*?)}`)
-	if err != nil {
-		return s
-	}
+	r := regexp.MustCompile(`\${(.*?)}`)
 	re := r.FindAllStringSubmatch(s, -1)
 	for _, i := range re {
 		if len(i) == 2 {
diff --git a/config/options_test.go b/config/options_test.go
index c3769166b..dd6bc538e 100644
--- a/config/options_test.go
+++ b/config/options_test.go
@@ -1,6 +1,7 @@
 package config
 
 import (
+	"reflect"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -35,3 +36,150 @@ func TestDefaultDecoder(t *testing.T) {
 		},
 	}, target)
 }
+
+func TestDefaultResolver(t *testing.T) {
+	var (
+		portString = "8080"
+		countInt   = 10
+		rateFloat  = 0.9
+	)
+
+	data := map[string]interface{}{
+		"foo": map[string]interface{}{
+			"bar": map[string]interface{}{
+				"notexist": "${NOTEXIST:100}",
+				"port":     "${PORT:8081}",
+				"count":    "${COUNT:0}",
+				"enable":   "${ENABLE:false}",
+				"rate":     "${RATE}",
+				"empty":    "${EMPTY:foobar}",
+				"url":      "${URL:http://example.com}",
+				"array": []interface{}{
+					"${PORT}",
+					map[string]interface{}{"foobar": "${NOTEXIST:8081}"},
+				},
+				"value1": "${test.value}",
+				"value2": "$PORT",
+				"value3": "abc${PORT}foo${COUNT}bar",
+				"value4": "${foo${bar}}",
+			},
+		},
+		"test": map[string]interface{}{
+			"value": "foobar",
+		},
+		"PORT":   "8080",
+		"COUNT":  "10",
+		"ENABLE": "true",
+		"RATE":   "0.9",
+		"EMPTY":  "",
+	}
+
+	tests := []struct {
+		name   string
+		path   string
+		expect interface{}
+	}{
+		{
+			name:   "test not exist int env with default",
+			path:   "foo.bar.notexist",
+			expect: 100,
+		},
+		{
+			name:   "test string with default",
+			path:   "foo.bar.port",
+			expect: portString,
+		},
+		{
+			name:   "test int with default",
+			path:   "foo.bar.count",
+			expect: countInt,
+		},
+		{
+			name:   "test bool with default",
+			path:   "foo.bar.enable",
+			expect: true,
+		},
+		{
+			name:   "test float without default",
+			path:   "foo.bar.rate",
+			expect: rateFloat,
+		},
+		{
+			name:   "test empty value with default",
+			path:   "foo.bar.empty",
+			expect: "",
+		},
+		{
+			name:   "test url with default",
+			path:   "foo.bar.url",
+			expect: "http://example.com",
+		},
+		{
+			name:   "test array",
+			path:   "foo.bar.array",
+			expect: []interface{}{portString, map[string]interface{}{"foobar": "8081"}},
+		},
+		{
+			name:   "test ${test.value}",
+			path:   "foo.bar.value1",
+			expect: "foobar",
+		},
+		{
+			name:   "test $PORT",
+			path:   "foo.bar.value2",
+			expect: "$PORT",
+		},
+		{
+			name:   "test abc${PORT}foo${COUNT}bar",
+			path:   "foo.bar.value3",
+			expect: "abc8080foo10bar",
+		},
+		{
+			name:   "test ${foo${bar}}",
+			path:   "foo.bar.value4",
+			expect: "}",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			err := defaultResolver(data)
+			assert.NoError(t, err)
+			rd := reader{
+				values: data,
+			}
+			if v, ok := rd.Value(test.path); ok {
+				var actual interface{}
+				switch test.expect.(type) {
+				case int:
+					if actual, err = v.Int(); err == nil {
+						assert.Equal(t, test.expect, int(actual.(int64)), "int value should be equal")
+					}
+				case string:
+					if actual, err = v.String(); err == nil {
+						assert.Equal(t, test.expect, actual, "string value should be equal")
+					}
+				case bool:
+					if actual, err = v.Bool(); err == nil {
+						assert.Equal(t, test.expect, actual, "bool value should be equal")
+					}
+				case float64:
+					if actual, err = v.Float(); err == nil {
+						assert.Equal(t, test.expect, actual, "float64 value should be equal")
+					}
+				default:
+					actual = v.Load()
+					if !reflect.DeepEqual(test.expect, actual) {
+						t.Logf("expect: %#v, actural: %#v", test.expect, actual)
+						t.Fail()
+					}
+				}
+				if err != nil {
+					t.Error(err)
+				}
+			} else {
+				t.Error("value path not found")
+			}
+		})
+	}
+}