package main import ( "fmt" "go/ast" "go/parser" "go/token" "io" "log" "os" "sort" "strconv" "strings" ) func process(path string, skipped map[string]map[string]int) { f, err := parser.ParseFile(new(token.FileSet), path, nil, 0) if err != nil { log.Fatalf("could not compile proc_test.go: %v", err) } ntests := 0 ast.Inspect(f, func(node ast.Node) bool { switch node := node.(type) { case *ast.File: return true case *ast.FuncDecl: if !strings.HasPrefix(node.Name.Name, "Test") { return false } ntests++ stmtLoop: for _, stmt := range node.Body.List { expr, isexpr := stmt.(*ast.ExprStmt) if !isexpr { continue } call, ok := expr.X.(*ast.CallExpr) if !ok { return false } fun, ok := call.Fun.(*ast.Ident) if !ok { return false } switch fun.Name { case "skipOn": reason, conditions := skipOnArgs(call.Args) if reason == "N/A" { ntests-- break stmtLoop } if skipped[conditions] == nil { skipped[conditions] = make(map[string]int) } skipped[conditions][reason]++ case "skipUnlessOn": ntests-- break stmtLoop } } } return false }) } func main() { skipped := make(map[string]map[string]int) process("pkg/proc/proc_test.go", skipped) process("pkg/proc/stepping_test.go", skipped) var fh io.WriteCloser if len(os.Args) > 1 && os.Args[1] == "-" { fh = os.Stdout } else { var err error fh, err = os.Create("./Documentation/backend_test_health.md") if err != nil { log.Fatalf("could not create backend_test_health.md: %v", err) } } fmt.Fprintf(fh, "Tests skipped by each supported backend:\n\n") conds := []string{} for cond := range skipped { conds = append(conds, cond) } sort.Strings(conds) for _, cond := range conds { tot := 0 for _, v := range skipped[cond] { tot += v } fmt.Fprintf(fh, "* %s skipped = %d\n", cond, tot) reasons := []string{} for reason := range skipped[cond] { reasons = append(reasons, reason) } sort.Strings(reasons) for _, reason := range reasons { fmt.Fprintf(fh, "\t* %d %s\n", skipped[cond][reason], reason) } } err := fh.Close() if err != nil { log.Fatalf("could not close output file: %v", err) } } func skipOnArgs(args []ast.Expr) (reason string, conditions string) { reason, _ = strconv.Unquote(args[1].(*ast.BasicLit).Value) conds := []string{} for _, arg := range args[2:] { cond, _ := strconv.Unquote(arg.(*ast.BasicLit).Value) conds = append(conds, cond) } conditions = strings.Join(conds, "/") return reason, conditions }