From b58701178de7b90fb823baddbcc5bff50d6fdbb2 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Tue, 28 Sep 2021 22:50:24 +0800 Subject: [PATCH] feat: parse variable --- parser.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ parser_test.go | 29 ++++++++++++++++++++++++++ response.go | 4 ++-- runner.go | 2 +- 4 files changed, 87 insertions(+), 3 deletions(-) diff --git a/parser.go b/parser.go index 48ec28d7..4540f777 100644 --- a/parser.go +++ b/parser.go @@ -1,8 +1,11 @@ package httpboomer import ( + "fmt" "log" "net/url" + "regexp" + "strings" ) func parseStep(step IStep, config *TConfig) *TStep { @@ -27,3 +30,55 @@ func buildURL(baseURL, stepURL string) string { // base url missed return uStep.String() } + +func parseData(raw interface{}, variablesMapping map[string]interface{}) interface{} { + switch v := raw.(type) { + case string: + v = strings.TrimSpace(v) + return parseString(v, variablesMapping) + default: + return raw + } +} + +var ( + regexCompileVariable = regexp.MustCompile(`\$\{(\w+)\}|\$(\w+)`) // parse ${var} or $var +) + +// parseString parse string with variables +func parseString(raw string, variablesMapping map[string]interface{}) interface{} { + matchStartPosition := strings.Index(raw, "$") + if matchStartPosition == -1 { // no $ found + return raw + } + parsedString := raw[0:matchStartPosition] + + for matchStartPosition < len(raw) { + // search variable like ${var} or $var + varMatched := regexCompileVariable.FindStringSubmatch(raw[matchStartPosition:]) + if len(varMatched) == 3 { + var varName string + if varMatched[1] != "" { + varName = varMatched[1] // match ${var} + } else { + varName = varMatched[2] // match $var + } + varValue := variablesMapping[varName] + + if fmt.Sprintf("${%s}", varName) == raw || fmt.Sprintf("$%s", varName) == raw { + // raw string is a variable, $var or ${var}, return its value directly + return varValue + } + + parsedString += fmt.Sprintf("%v", varValue) + matchStartPosition += len(varMatched[0]) + log.Printf("[parseString] parsedString: %v, matchStartPosition: %v", parsedString, matchStartPosition) + continue + } + + // append remained string + parsedString += raw[matchStartPosition:] + } + + return parsedString +} diff --git a/parser_test.go b/parser_test.go index 5e1b67ac..c6ff2576 100644 --- a/parser_test.go +++ b/parser_test.go @@ -2,6 +2,8 @@ package httpboomer import ( "testing" + + "github.com/stretchr/testify/assert" ) func TestBuildURL(t *testing.T) { @@ -27,3 +29,30 @@ func TestBuildURL(t *testing.T) { t.Fatalf("buildURL error, %s != 'https://httpbin.org/get'", url) } } + +func TestParseDataStringWithVariables(t *testing.T) { + variablesMapping := map[string]interface{}{ + "var_1": "abc", + "var_2": "def", + "var_3": 123, + "var_4": map[string]interface{}{"a": 1}, + "var_5": true, + "var_6": nil, + } + + if !assert.Equal(t, "abc", parseData("$var_1", variablesMapping)) { + t.Fail() + } + if !assert.Equal(t, "abc", parseData("${var_1}", variablesMapping)) { + t.Fail() + } + if !assert.Equal(t, "var_1", parseData("var_1", variablesMapping)) { + t.Fail() + } + if !assert.Equal(t, "abc#XYZ", parseData("$var_1#XYZ", variablesMapping)) { + t.Fail() + } + if !assert.Equal(t, "abc#XYZ", parseData("${var_1}#XYZ", variablesMapping)) { + t.Fail() + } +} diff --git a/response.go b/response.go index 5d4cba91..25a70704 100644 --- a/response.go +++ b/response.go @@ -80,7 +80,7 @@ type ResponseObject struct { validationResults map[string]interface{} } -func (v *ResponseObject) Validate(validators []TValidator) error { +func (v *ResponseObject) Validate(validators []TValidator, variablesMapping map[string]interface{}) error { for _, validator := range validators { // parse check value checkItem := validator.Check @@ -89,7 +89,7 @@ func (v *ResponseObject) Validate(validators []TValidator) error { assertMethod := validator.Assert assertFunc := assertFunctionsMap[assertMethod] // parse expected value - expectValue := validator.Expect + expectValue := parseData(validator.Expect, variablesMapping) // do assertion result := assertFunc(v.t, expectValue, checkValue) log.Printf("assert %s %s %v => %v", checkItem, assertMethod, expectValue, result) diff --git a/runner.go b/runner.go index 9ac2ff56..978a9e2a 100644 --- a/runner.go +++ b/runner.go @@ -107,7 +107,7 @@ func (r *Runner) runStepRequest(step *TStep) error { // validate response respObj := NewResponseObject(r.t, resp) - err = respObj.Validate(step.Validators) + err = respObj.Validate(step.Validators, step.Variables) if err != nil { return err }