package gen import ( "github.com/easysoft/zendata/src/model" commonUtils "github.com/easysoft/zendata/src/utils/common" constant "github.com/easysoft/zendata/src/utils/const" fileUtils "github.com/easysoft/zendata/src/utils/file" "github.com/easysoft/zendata/src/utils/vari" "math" "strconv" "strings" ) func CreateListField(field *model.DefField, fieldWithValue *model.FieldWithValues) { fieldWithValue.Field = field.Field fieldWithValue.Precision = field.Precision if len(field.Fields) > 0 { for _, child := range field.Fields { childFieldWithValue := model.FieldWithValues{} CreateListField(&child, &childFieldWithValue) } } else { CreateListFieldValues(field, fieldWithValue) } } func CreateListFieldValues(field *model.DefField, fieldValue *model.FieldWithValues) { if strings.Index(field.Range, ".txt") > -1 { CreateFieldValuesFromText(field, fieldValue) } else { CreateFieldValuesFromList(field, fieldValue) } } func CreateFieldValuesFromList(field *model.DefField, fieldValue *model.FieldWithValues) { rang := field.Range if rang == "" { for i := 0; i < vari.Total; i++ { fieldValue.Values = append(fieldValue.Values, "") } return } rangeSections := ParseRangeProperty(rang) // parse 1 index := 0 for _, rangeSection := range rangeSections { if index >= constant.MaxNumb { break } if rangeSection == "" { continue } descStr, stepStr, count, countTag := ParseRangeSection(rangeSection) // parse 2 if strings.ToLower(stepStr) == "r" { (*field).IsRand = true } typ, desc := ParseRangeSectionDesc(descStr) // parse 3 items := make([]interface{}, 0) if typ == "literal" { items = CreateValuesFromLiteral(field, desc, stepStr, count, countTag) } else if typ == "interval" { items = CreateValuesFromInterval(field, desc, stepStr, count, countTag) } else if typ == "yaml" { // load from a yaml items = CreateValuesFromYaml(field, desc, stepStr, count, countTag) field.ReferToAnotherYaml = true } fieldValue.Values = append(fieldValue.Values, items...) index = index + len(items) } if len(fieldValue.Values) == 0 { fieldValue.Values = append(fieldValue.Values, "N/A") } } func CheckRangeType(startStr string, endStr string, stepStr string) (dataType string, step interface{}, precision int, rand bool, count int) { step = 1 stepStr = strings.ToLower(strings.TrimSpace(stepStr)) int1, errInt1 := strconv.ParseInt(startStr, 0, 64) int2, errInt2 := strconv.ParseInt(endStr, 0, 64) var errInt3 error if stepStr != "" && stepStr != "r" { _, errInt3 = strconv.ParseInt(stepStr, 0, 64) } if errInt1 == nil && errInt2 == nil && errInt3 == nil { // is int if stepStr != "" && stepStr != "r" { stepInt, errInt3 := strconv.Atoi(stepStr) if errInt3 == nil { step = stepInt } } else if stepStr == "r" { rand = true } if (int1 > int2 && step.(int) > 0) || (int1 < int2 && step.(int) < 0) { step = -1 * step.(int) } dataType = "int" count = (int)(int1-int2) / step.(int) if count < 0 { count = count * -1 } return } else { float1, errFloat1 := strconv.ParseFloat(startStr, 64) float2, errFloat2 := strconv.ParseFloat(endStr, 64) var errFloat3 error if stepStr != "" && stepStr != "r" { _, errFloat3 = strconv.ParseFloat(stepStr, 64) } if errFloat1 == nil && errFloat2 == nil && errFloat3 == nil { // is float if stepStr != "" && stepStr != "r" { stepFloat, errFloat3 := strconv.ParseFloat(stepStr, 64) if errFloat3 == nil { step = stepFloat } } else if stepStr == "r" { rand = true } precision1, step1 := GetPrecision(float1, step) precision2, step2 := GetPrecision(float2, step) if precision1 < precision2 { precision = precision2 step = step2 } else { precision = precision1 step = step1 } if (float1 > float2 && step.(float64) > 0) || (float1 < float2 && step.(float64) < 0) { step = -1 * step.(float64) } dataType = "float" count = int(math.Floor((float1-float2)/step.(float64) + 0/5)) if count < 0 { count = count * -1 } return } else if len(startStr) == 1 && len(endStr) == 1 { // is char if stepStr != "r" { stepChar, errChar3 := strconv.Atoi(stepStr) if errChar3 == nil { step = stepChar } } else if stepStr == "r" { rand = true } if (strings.Compare(startStr, endStr) > 0 && step.(int) > 0) || (strings.Compare(startStr, endStr) < 0 && step.(int) < 0) { step = -1 * step.(int) } dataType = "char" startChar := startStr[0] endChar := endStr[0] gap := 0 if endChar > startChar { // 负数转uint单独处理 gap = int(endChar - startChar) } else { gap = int(startChar - endChar) } count = gap / step.(int) if count < 0 { count = count * -1 } return } } dataType = "string" step = 1 return } func CreateValuesFromLiteral(field *model.DefField, desc string, stepStr string, repeat int, repeatTag string) (items []interface{}) { elemArr := ParseDesc(desc) step, _ := strconv.Atoi(stepStr) if step == 0 { step = 1 } total := 0 if field.Path != "" && stepStr == "r" { items = append(items, Placeholder(field.Path)) mp := placeholderMapForRandValues("list", elemArr, "", "", "", "", field.Format, repeat, repeatTag) vari.RandFieldNameToValuesMap[field.Path] = mp return } if repeatTag == "" { for i := 0; i < len(elemArr); { idx := i if field.Path == "" && stepStr == "r" { idx = commonUtils.RandNum(len(elemArr)) // should set random here too } val := elemArr[idx] total = appendValues(&items, val, repeat, total) if total >= constant.MaxNumb { break } i += step } } else if repeatTag == "!" { isRand := field.Path == "" && stepStr == "r" for i := 0; i < repeat; { total = appendArrItems(&items, elemArr, total, isRand) if total >= constant.MaxNumb { break } i += step } } if field.Path == "" && stepStr == "r" { // for ranges and instances, random items = randomInterfaces(items) } return } func CreateValuesFromInterval(field *model.DefField, desc, stepStr string, repeat int, repeatTag string) (items []interface{}) { elemArr := strings.Split(desc, "-") startStr := elemArr[0] endStr := startStr if len(elemArr) > 1 { endStr = elemArr[1] } dataType, step, precision, rand, count := CheckRangeType(startStr, endStr, stepStr) // 1. random replacement if field.Path != "" && dataType != "string" && rand { // random. for res, field.Path == "" val := Placeholder(field.Path + "->" + desc) strItems := make([]string, 0) for i := 0; i < repeat*count; i++ { items = append(items, val) strItems = append(strItems, val) } mp := placeholderMapForRandValues(dataType, strItems, startStr, endStr, stepStr, strconv.Itoa(precision), field.Format, repeat, repeatTag) vari.RandFieldNameToValuesMap[field.Path+"->"+desc] = mp return } if dataType == "int" { startInt, _ := strconv.ParseInt(startStr, 0, 64) endInt, _ := strconv.ParseInt(endStr, 0, 64) items = GenerateIntItems(startInt, endInt, step.(int), rand, repeat, repeatTag) } else if dataType == "float" { startFloat, _ := strconv.ParseFloat(startStr, 64) endFloat, _ := strconv.ParseFloat(endStr, 64) field.Precision = precision items = GenerateFloatItems(startFloat, endFloat, step, rand, precision, repeat, repeatTag) } else if dataType == "char" { items = GenerateByteItems(startStr[0], endStr[0], step.(int), rand, repeat, repeatTag) } else if dataType == "string" { if repeat == 0 { repeat = 1 } for i := 0; i < repeat; i++ { items = append(items, desc) } } if field.Path == "" && stepStr == "r" { // for ranges and instances, random again items = randomInterfaces(items) } return } func CreateValuesFromYaml(field *model.DefField, yamlFile, stepStr string, repeat int, repeatTag string) (items []interface{}) { // keep root def, since vari.ZdDef will be overwrite by refer yaml file rootDef := vari.Def configDir := vari.ConfigFileDir res := vari.Res configFile := fileUtils.ComputerReferFilePath(yamlFile, field) fieldsToExport := make([]string, 0) // set to empty to use all fields rows, colIsNumArr, _ := GenerateFromYaml([]string{configFile}, &fieldsToExport) if field.Rand { rows = randomValuesArr(rows) } items = Print(rows, constant.FormatData, "", colIsNumArr, fieldsToExport) if repeat > 0 { if repeat > len(items) { repeat = len(items) } items = items[:repeat] } // rollback root def when finish to deal with refer yaml file vari.Def = rootDef vari.ConfigFileDir = configDir vari.Res = res return } func Placeholder(str string) string { return "${" + str + "}" } func placeholderMapForRandValues(tp string, list []string, start, end, step, precision, format string, repeat int, repeatTag string) map[string]interface{} { ret := map[string]interface{}{} ret["type"] = tp // for literal values ret["list"] = list // for interval values ret["start"] = start ret["end"] = end ret["step"] = step ret["precision"] = precision ret["format"] = format ret["repeat"] = repeat ret["repeatTag"] = repeatTag return ret } func appendValues(items *[]interface{}, val string, repeat int, total int) int { for round := 0; round < repeat; round++ { *items = append(*items, val) total++ if total > constant.MaxNumb { break } } return total } func appendArrItems(items *[]interface{}, arr []string, total int, isRand bool) int { for i := 0; i < len(arr); i++ { idx := i if isRand { idx = commonUtils.RandNum(len(arr)) // should set random here too } *items = append(*items, arr[idx]) total++ if total > constant.MaxNumb { break } } return total }