github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/test/ssa_test.go (about) 1 // Copyright 2015 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 package test 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/ast" 11 "go/parser" 12 "go/token" 13 "os" 14 "path/filepath" 15 "runtime" 16 "strings" 17 "testing" 18 19 "github.com/go-asm/go/testenv" 20 ) 21 22 // runGenTest runs a test-generator, then runs the generated test. 23 // Generated test can either fail in compilation or execution. 24 // The environment variable parameter(s) is passed to the run 25 // of the generated test. 26 func runGenTest(t *testing.T, filename, tmpname string, ev ...string) { 27 testenv.MustHaveGoRun(t) 28 gotool := testenv.GoToolPath(t) 29 var stdout, stderr bytes.Buffer 30 cmd := testenv.Command(t, gotool, "run", filepath.Join("testdata", filename)) 31 cmd.Stdout = &stdout 32 cmd.Stderr = &stderr 33 if err := cmd.Run(); err != nil { 34 t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr) 35 } 36 // Write stdout into a temporary file 37 rungo := filepath.Join(t.TempDir(), "run.go") 38 ok := os.WriteFile(rungo, stdout.Bytes(), 0600) 39 if ok != nil { 40 t.Fatalf("Failed to create temporary file " + rungo) 41 } 42 43 stdout.Reset() 44 stderr.Reset() 45 cmd = testenv.Command(t, gotool, "run", "-gcflags=-d=ssa/check/on", rungo) 46 cmd.Stdout = &stdout 47 cmd.Stderr = &stderr 48 cmd.Env = append(cmd.Env, ev...) 49 err := cmd.Run() 50 if err != nil { 51 t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr) 52 } 53 if s := stderr.String(); s != "" { 54 t.Errorf("Stderr = %s\nWant empty", s) 55 } 56 if s := stdout.String(); s != "" { 57 t.Errorf("Stdout = %s\nWant empty", s) 58 } 59 } 60 61 func TestGenFlowGraph(t *testing.T) { 62 if testing.Short() { 63 t.Skip("not run in short mode.") 64 } 65 runGenTest(t, "flowgraph_generator1.go", "ssa_fg_tmp1") 66 } 67 68 // TestCode runs all the tests in the testdata directory as subtests. 69 // These tests are special because we want to run them with different 70 // compiler flags set (and thus they can't just be _test.go files in 71 // this directory). 72 func TestCode(t *testing.T) { 73 testenv.MustHaveGoBuild(t) 74 gotool := testenv.GoToolPath(t) 75 76 // Make a temporary directory to work in. 77 tmpdir := t.TempDir() 78 79 // Find all the test functions (and the files containing them). 80 var srcs []string // files containing Test functions 81 type test struct { 82 name string // TestFoo 83 usesFloat bool // might use float operations 84 } 85 var tests []test 86 files, err := os.ReadDir("testdata") 87 if err != nil { 88 t.Fatalf("can't read testdata directory: %v", err) 89 } 90 for _, f := range files { 91 if !strings.HasSuffix(f.Name(), "_test.go") { 92 continue 93 } 94 text, err := os.ReadFile(filepath.Join("testdata", f.Name())) 95 if err != nil { 96 t.Fatalf("can't read testdata/%s: %v", f.Name(), err) 97 } 98 fset := token.NewFileSet() 99 code, err := parser.ParseFile(fset, f.Name(), text, 0) 100 if err != nil { 101 t.Fatalf("can't parse testdata/%s: %v", f.Name(), err) 102 } 103 srcs = append(srcs, filepath.Join("testdata", f.Name())) 104 foundTest := false 105 for _, d := range code.Decls { 106 fd, ok := d.(*ast.FuncDecl) 107 if !ok { 108 continue 109 } 110 if !strings.HasPrefix(fd.Name.Name, "Test") { 111 continue 112 } 113 if fd.Recv != nil { 114 continue 115 } 116 if fd.Type.Results != nil { 117 continue 118 } 119 if len(fd.Type.Params.List) != 1 { 120 continue 121 } 122 p := fd.Type.Params.List[0] 123 if len(p.Names) != 1 { 124 continue 125 } 126 s, ok := p.Type.(*ast.StarExpr) 127 if !ok { 128 continue 129 } 130 sel, ok := s.X.(*ast.SelectorExpr) 131 if !ok { 132 continue 133 } 134 base, ok := sel.X.(*ast.Ident) 135 if !ok { 136 continue 137 } 138 if base.Name != "testing" { 139 continue 140 } 141 if sel.Sel.Name != "T" { 142 continue 143 } 144 // Found a testing function. 145 tests = append(tests, test{name: fd.Name.Name, usesFloat: bytes.Contains(text, []byte("float"))}) 146 foundTest = true 147 } 148 if !foundTest { 149 t.Fatalf("test file testdata/%s has no tests in it", f.Name()) 150 } 151 } 152 153 flags := []string{""} 154 if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" || runtime.GOARCH == "386" { 155 flags = append(flags, ",softfloat") 156 } 157 for _, flag := range flags { 158 args := []string{"test", "-c", "-gcflags=-d=ssa/check/on" + flag, "-o", filepath.Join(tmpdir, "code.test")} 159 args = append(args, srcs...) 160 out, err := testenv.Command(t, gotool, args...).CombinedOutput() 161 if err != nil || len(out) != 0 { 162 t.Fatalf("Build failed: %v\n%s\n", err, out) 163 } 164 165 // Now we have a test binary. Run it with all the tests as subtests of this one. 166 for _, test := range tests { 167 test := test 168 if flag == ",softfloat" && !test.usesFloat { 169 // No point in running the soft float version if the test doesn't use floats. 170 continue 171 } 172 t.Run(fmt.Sprintf("%s%s", test.name[4:], flag), func(t *testing.T) { 173 out, err := testenv.Command(t, filepath.Join(tmpdir, "code.test"), "-test.run=^"+test.name+"$").CombinedOutput() 174 if err != nil || string(out) != "PASS\n" { 175 t.Errorf("Failed:\n%s\n", out) 176 } 177 }) 178 } 179 } 180 }