package main import ( "encoding/json" "flag" "fmt" "os" "reflect" "runtime" "strconv" "strings" "time" "github.com/iancoleman/orderedmap" ) var testDefinitions *TestDefinitions var captureValues *CaptureValues func PrintStructContents(s interface{}, indentLevel int) string { var result strings.Builder val := reflect.ValueOf(s) if val.Kind() == reflect.Ptr { val = val.Elem() } typ := val.Type() for i := 0; i < val.NumField(); i++ { field := val.Field(i) fieldType := typ.Field(i) indent := strings.Repeat("\t", indentLevel) result.WriteString(fmt.Sprintf("%s%s: ", indent, fieldType.Name)) switch field.Kind() { case reflect.Struct: result.WriteString("\n") result.WriteString(PrintStructContents(field.Interface(), indentLevel+1)) default: result.WriteString(fmt.Sprintf("%v\n", field.Interface())) } } return result.String() } func main() { var s []byte var err error //var ok bool // Prepare struct to store settings common to all tests testDefinitions = new(TestDefinitions) captureValues = new(CaptureValues) captureValues.Data = make(map[string]string) // Command line arguments var inputJson string // Process command line arguments flag.StringVar(&inputJson, "input", "./tests.json", "Full path to input json test definition file") flag.Parse() // Read the json input file if fileExists(inputJson) { s, err = os.ReadFile(inputJson) if err != nil { panic(err) } } else { fmt.Printf("Input JSON file '%s' does not exist.\n", inputJson) os.Exit(1) } // Process the input json ReadInput(s, testDefinitions) //fmt.Println(PrintStructContents(testDefinitions.TestCases[1], 0)) // Perform specified test cases for i := range testDefinitions.TestCases { if testDefinitions.TestCases[i].Disabled { fmt.Printf("\nSkipping disabled test '%s'\n", testDefinitions.TestCases[i].Name) continue } RunTest(&testDefinitions.TestCases[i]) fmt.Printf("\nRunning checks on output\n") success, err := CheckResults(&testDefinitions.TestCases[i]) if err != nil { fmt.Printf("Error running test case : %s\n", err) os.Exit(1) } if !success { fmt.Printf("Test result failed\n") os.Exit(1) } else { fmt.Printf("\nTest '%s' successful\n", testDefinitions.TestCases[i].Name) } } fmt.Printf("\nCongratulations, all tests passed!\n\n") // For debugging, just dump the output //fmt.Printf("%+v\n", testDefinitions) //fmt.Println(PrintStructContents(testDefinitions, 0)) } // fileExists returns true if the specified file exists and is not a directory func fileExists(filename string) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { return false } return !info.IsDir() } func OrderedToStringMap(input orderedmap.OrderedMap) map[string]string { result := make(map[string]string) mapKeys := input.Keys() for _, bodyKey := range mapKeys { if bodyVal, ok := input.Get(bodyKey); ok { switch vType := bodyVal.(type) { case string: result[bodyKey] = bodyVal.(string) case bool: result[bodyKey] = strconv.FormatBool(bodyVal.(bool)) default: fmt.Printf("OrderedToStringMap received unexpected value type, %T\n", vType) } } } return result } func OrderedToStringSlice(input []interface{}) []string { result := []string{} for i := range input { switch vType := input[i].(type) { // TODO : more types case string: result = append(result, input[i].(string)) default: fmt.Printf("OrderedToStringSlice received unexpected value type, %T\n", vType) } } return result } // prettyPrint comes from https://gist.github.com/sfate/9d45f6c5405dc4c9bf63bf95fe6d1a7c func prettyPrint(args ...interface{}) { var caller string timeNow := time.Now().Format("01-02-2006 15:04:05") prefix := fmt.Sprintf("[%s] %s -- ", "PrettyPrint", timeNow) _, fileName, fileLine, ok := runtime.Caller(1) if ok { caller = fmt.Sprintf("%s:%d", fileName, fileLine) } else { caller = "" } fmt.Printf("\n%s%s\n", prefix, caller) if len(args) == 2 { label := args[0] value := args[1] s, _ := json.MarshalIndent(value, "", "\t") fmt.Printf("%s%s: %s\n", prefix, label, string(s)) } else { s, _ := json.MarshalIndent(args, "", "\t") fmt.Printf("%s%s\n", prefix, string(s)) } }