1// Copyright 2023 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5//go:build ignore 6 7package main 8 9import ( 10 "bytes" 11 "fmt" 12 "internal/trace/raw" 13 "internal/trace/version" 14 "internal/txtar" 15 "io" 16 "log" 17 "os" 18 "os/exec" 19 "path/filepath" 20 "regexp" 21) 22 23func main() { 24 log.SetFlags(0) 25 ctx, err := newContext() 26 if err != nil { 27 log.Fatal(err) 28 } 29 if err := ctx.runGenerators(); err != nil { 30 log.Fatal(err) 31 } 32 if err := ctx.runTestProg("./testprog/annotations.go"); err != nil { 33 log.Fatal(err) 34 } 35 if err := ctx.runTestProg("./testprog/annotations-stress.go"); err != nil { 36 log.Fatal(err) 37 } 38} 39 40type context struct { 41 testNames map[string]struct{} 42 filter *regexp.Regexp 43} 44 45func newContext() (*context, error) { 46 var filter *regexp.Regexp 47 var err error 48 if pattern := os.Getenv("GOTRACETEST"); pattern != "" { 49 filter, err = regexp.Compile(pattern) 50 if err != nil { 51 return nil, fmt.Errorf("compiling regexp %q for GOTRACETEST: %v", pattern, err) 52 } 53 } 54 return &context{ 55 testNames: make(map[string]struct{}), 56 filter: filter, 57 }, nil 58} 59 60func (ctx *context) register(testName string) (skip bool, err error) { 61 if _, ok := ctx.testNames[testName]; ok { 62 return true, fmt.Errorf("duplicate test %s found", testName) 63 } 64 if ctx.filter != nil { 65 return !ctx.filter.MatchString(testName), nil 66 } 67 return false, nil 68} 69 70func (ctx *context) runGenerators() error { 71 generators, err := filepath.Glob("./generators/*.go") 72 if err != nil { 73 return fmt.Errorf("reading generators: %v", err) 74 } 75 genroot := "./tests" 76 77 if err := os.MkdirAll(genroot, 0777); err != nil { 78 return fmt.Errorf("creating generated root: %v", err) 79 } 80 for _, path := range generators { 81 name := filepath.Base(path) 82 name = name[:len(name)-len(filepath.Ext(name))] 83 84 // Skip if we have a pattern and this test doesn't match. 85 skip, err := ctx.register(name) 86 if err != nil { 87 return err 88 } 89 if skip { 90 continue 91 } 92 93 fmt.Fprintf(os.Stderr, "generating %s... ", name) 94 95 // Get the test path. 96 testPath := filepath.Join(genroot, fmt.Sprintf("%s.test", name)) 97 98 // Run generator. 99 cmd := exec.Command("go", "run", path, testPath) 100 if out, err := cmd.CombinedOutput(); err != nil { 101 return fmt.Errorf("running generator %s: %v:\n%s", name, err, out) 102 } 103 fmt.Fprintln(os.Stderr) 104 } 105 return nil 106} 107 108func (ctx *context) runTestProg(progPath string) error { 109 name := filepath.Base(progPath) 110 name = name[:len(name)-len(filepath.Ext(name))] 111 name = fmt.Sprintf("go1%d-%s", version.Current, name) 112 113 // Skip if we have a pattern and this test doesn't match. 114 skip, err := ctx.register(name) 115 if err != nil { 116 return err 117 } 118 if skip { 119 return nil 120 } 121 122 // Create command. 123 var trace, stderr bytes.Buffer 124 cmd := exec.Command("go", "run", progPath) 125 cmd.Stdout = &trace 126 cmd.Stderr = &stderr 127 128 // Run trace program; the trace will appear in stdout. 129 fmt.Fprintf(os.Stderr, "running trace program %s...\n", name) 130 if err := cmd.Run(); err != nil { 131 log.Fatalf("running trace program: %v:\n%s", err, stderr.String()) 132 } 133 134 // Write out the trace. 135 var textTrace bytes.Buffer 136 r, err := raw.NewReader(&trace) 137 if err != nil { 138 log.Fatalf("reading trace: %v", err) 139 } 140 w, err := raw.NewTextWriter(&textTrace, version.Current) 141 for { 142 ev, err := r.ReadEvent() 143 if err == io.EOF { 144 break 145 } 146 if err != nil { 147 log.Fatalf("reading trace: %v", err) 148 } 149 if err := w.WriteEvent(ev); err != nil { 150 log.Fatalf("writing trace: %v", err) 151 } 152 } 153 testData := txtar.Format(&txtar.Archive{ 154 Files: []txtar.File{ 155 {Name: "expect", Data: []byte("SUCCESS")}, 156 {Name: "trace", Data: textTrace.Bytes()}, 157 }, 158 }) 159 return os.WriteFile(fmt.Sprintf("./tests/%s.test", name), testData, 0o664) 160} 161