package odbcmql import ( "encoding/json" "fmt" "regexp" "strconv" "strings" "testing" "git.wecise.com/wecise/odb-go/odb" "gitee.com/wecisecode/util/cast" "gitee.com/wecisecode/util/merrs" "github.com/stretchr/testify/assert" ) func DoActionMatch(t *testing.T, args []any, mql string, rtn *odb.Result, toption *OnErrorOption) (breakup bool, seriouserror bool, err error) { if len(args) < 2 { s := "match(Kn,Mn) 需要至少两个参数" err = merrs.New("%s", s) assert.Nil(t, s, err) seriouserror = true breakup = true return } ks := []string{} ms := []any{} i := 0 for ; i+1 < len(args); i += 2 { k := strings.TrimSpace(cast.ToString(args[i])) ks = append(ks, k) var m any switch arg := args[i+1].(type) { case string: if regexp.MustCompile(`^\(\?[^\)]*\).*`).MatchString(arg) { r, e := regexp.Compile(arg) if e != nil { s := "match参数正则表达式错误:" + e.Error() err = merrs.New("%s", s) assert.Nil(t, s, err) seriouserror = true breakup = true return } m = r } } if m == nil { m = fmt.Sprintf("%#v", args[i+1]) } ms = append(ms, m) } if i > len(args) { err = merrs.New("match(Kn,Mn) 参数 Kn,Mn 需要成对出现") assert.Nil(t, "参数错误", err) seriouserror = true breakup = true return } x := 0 var matchingvalues [][]any var matchingvalue any for _, dat := range rtn.Data { matchingvalues = append(matchingvalues, []any{}) m := false sv := "" match := true for i, k := range ks { matchingvalue = dat[k] m, sv = matchvalue(ms[i], matchingvalue) if !m { ks := strings.Split(k, ".") if len(ks) <= 1 { match = false break } else { k := "" for i := 0; match && i < len(ks); i++ { if matchingvalue == nil { if k != "" { k += "." } k += ks[i] matchingvalue = dat[k] if matchingvalue == nil && ks[i] == "len" { matchingvalue = 0 } } else { switch mv := matchingvalue.(type) { case map[string]any: matchingvalue = mv[ks[i]] if matchingvalue == nil && ks[i] == "len" { matchingvalue = len(mv) } case []any: if ks[i] == "len" { matchingvalue = len(mv) } else { n, e := cast.ToIntE(ks[i]) if e != nil { match = false break } matchingvalue = mv[n] } case string: if ks[i] == "len" { matchingvalue = len(mv) } else { n, e := cast.ToIntE(ks[i]) if e != nil { match = false break } matchingvalue = mv[n] } default: if ks[i] == "len" { matchingvalue = 0 } else { matchingvalue = nil } } } } m, sv = matchvalue(ms[i], matchingvalue) if !m { match = false break } } } matchingvalues[len(matchingvalues)-1] = append(matchingvalues[len(matchingvalues)-1], sv) } if match { x++ matchingvalues = matchingvalues[:len(matchingvalues)-1] } else { matchingvalues[len(matchingvalues)-1] = append(matchingvalues[len(matchingvalues)-1], sv) } } if x == 0 { if len(rtn.Data) == 0 { err = merrs.New("%s", "没有找到记录与期望值不符") } else { argsbs, _ := json.MarshalIndent(args, "", " ") matchingbs, _ := json.MarshalIndent(matchingvalues, "", " ") err = merrs.NewError(fmt.Sprint("共", len(rtn.Data), "记录,没有找到记录与期望值不符"), merrs.SSMaps{{"mql": mql}, {"match args": fmt.Sprint(string(argsbs))}, {"lastmatchingvalues": string(matchingbs)}}) } if toption.regex[OnErrorBreak] != nil && toption.regex[OnErrorBreak].MatchString(err.Error()) { if toption.regex[OnErrorBreak] == matchall && !toption.noerrorinfo { logger.Info("error:", err) } breakup = true return } if toption.regex[OnErrorIgnore] != nil && toption.regex[OnErrorIgnore].MatchString(err.Error()) { // 直接输出错误信息,不返回错误信息,不中断循环, 不在 testing.T 中报告错误,不中断测试 if toption.regex[OnErrorIgnore] == matchall && !toption.noerrorinfo { logger.Info("pass_with_error:", err) } err = nil breakup = true return } if !assert.Nil(t, "error", err) { // 不直接输出错误信息,返回错误信息,中断循环, 在 testing.T 中报告错误,中断测试 breakup = true return } } return } func DoActionEqual(t *testing.T, toption *OnErrorOption, result *odb.Result, args ...string) (breakup bool, seriouserror bool, err error) { if len(args) < 3 { err = merrs.New("%s", "equal(N,F,V) 需要三个参数") assert.Nil(t, "参数错误", err) seriouserror = true breakup = true return } n := cast.ToInt(strings.TrimSpace(args[0])) for kvi := 1; kvi+1 < len(args); kvi += 2 { field := strings.TrimSpace(args[kvi]) value := strings.TrimSpace(args[kvi+1]) if len(value) > 1 && value[0] == '"' && value[len(value)-1] == '"' { x, e := strconv.Unquote(value) if e != nil { err = merrs.New("%s V:%s", "equal(N,F,V) 参数 V 格式错误", value) assert.Nil(t, "参数错误", err) seriouserror = true breakup = true return } value = x } if n < 0 && result.Meta != nil { dat := result.Meta breakup, seriouserror, err = DeepEqual(t, toption, dat, field, value) if breakup { return } } else if len(result.Data) > n && result.Data[n] != nil { dat := result.Data[n] breakup, seriouserror, err = DeepEqual(t, toption, dat, field, value) if breakup { return } } else { err = merrs.New("%s", fmt.Sprint("字段 ", field, " 实际值(不存在)与期望值(", value, ")不符")) if toption.regex[OnErrorBreak] != nil && toption.regex[OnErrorBreak].MatchString(err.Error()) { if toption.regex[OnErrorBreak] == matchall && !toption.noerrorinfo { logger.Info("error:", err) } breakup = true return } if toption.regex[OnErrorIgnore] != nil && toption.regex[OnErrorIgnore].MatchString(err.Error()) { // 直接输出错误信息,不返回错误信息,不中断循环, 不在 testing.T 中报告错误,不中断测试 if toption.regex[OnErrorIgnore] == matchall && !toption.noerrorinfo { logger.Info("pass_with_error:", err) } err = nil return } if !assert.Equal(t, value, "", err) { // 不直接输出错误信息,返回错误信息,中断循环, 在 testing.T 中报告错误,中断测试 return } } } return } func DeepEqual(t *testing.T, toption *OnErrorOption, dat map[string]any, field, value string) (breakup bool, seriouserror bool, err error) { kks := strings.Split(field, ".") kki := len(kks) v := "" var vv any for ; vv == nil && kki >= 1; kki-- { kk := strings.Join(kks[:kki], ".") vv = dat[kk] for ; vv != nil && kki < len(kks); kki++ { switch mv := vv.(type) { case map[string]any: vv = mv[kks[kki]] if vv == nil { if kks[kki] == "len" { vv = len(mv) } } case map[string][]string: vvs := mv[kks[kki]] if vvs == nil { if kks[kki] == "len" { vv = len(mv) } } else { vv = vvs } case map[string][]any: vvs := mv[kks[kki]] if vvs == nil { if kks[kki] == "len" { vv = len(mv) } } else { vv = vvs } case []any: if kks[kki] == "len" { vv = len(mv) } else { sik := strings.TrimSpace(kks[kki]) ik, e := strconv.Atoi(sik) if e != nil { err = merrs.New("%s V:%s", "equal(N,F,V) 参数 V 格式错误", field) assert.Nil(t, "参数错误", err) seriouserror = true breakup = true return } vv = mv[ik] } case []string: if kks[kki] == "len" { vv = len(mv) } else { sik := strings.TrimSpace(kks[kki]) ik, e := strconv.Atoi(sik) if e != nil { err = merrs.New("%s V:%s", "equal(N,F,V) 参数 V 格式错误", field) assert.Nil(t, "参数错误", err) seriouserror = true breakup = true return } vv = mv[ik] } } } } v = fmt.Sprint(vv) if v != value { err = merrs.New("%s", fmt.Sprint("字段 ", field, " 实际值(", v, ")与期望值(", value, ")不符")) if toption.regex[OnErrorBreak] != nil && toption.regex[OnErrorBreak].MatchString(err.Error()) { if toption.regex[OnErrorBreak] == matchall && !toption.noerrorinfo { logger.Info("error:", err) } breakup = true return } if toption.regex[OnErrorIgnore] != nil && toption.regex[OnErrorIgnore].MatchString(err.Error()) { // 直接输出错误信息,不返回错误信息,不中断循环, 不在 testing.T 中报告错误,不中断测试 if toption.regex[OnErrorIgnore] == matchall && !toption.noerrorinfo { logger.Info("pass_with_error:", err) } err = nil return } if !assert.Equal(t, value, v, err) { breakup = true return } } return }