golang.org/x/tools@v0.21.0/refactor/eg/eg_test.go (about) 1 // Copyright 2014 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 // No testdata on Android. 6 7 //go:build !android 8 // +build !android 9 10 package eg_test 11 12 import ( 13 "bytes" 14 "flag" 15 "go/build" 16 "go/constant" 17 "go/parser" 18 "go/token" 19 "go/types" 20 "os" 21 "os/exec" 22 "path/filepath" 23 "runtime" 24 "strings" 25 "testing" 26 27 "golang.org/x/tools/go/loader" 28 "golang.org/x/tools/internal/testenv" 29 "golang.org/x/tools/refactor/eg" 30 ) 31 32 // TODO(adonovan): more tests: 33 // - of command-line tool 34 // - of all parts of syntax 35 // - of applying a template to a package it imports: 36 // the replacement syntax should use unqualified names for its objects. 37 38 var ( 39 updateFlag = flag.Bool("update", false, "update the golden files") 40 verboseFlag = flag.Bool("verbose", false, "show matcher information") 41 ) 42 43 func Test(t *testing.T) { 44 testenv.NeedsTool(t, "go") 45 46 switch runtime.GOOS { 47 case "windows": 48 t.Skipf("skipping test on %q (no /usr/bin/diff)", runtime.GOOS) 49 } 50 51 ctx := build.Default // copy 52 ctx.CgoEnabled = false // don't use cgo 53 conf := loader.Config{ 54 Fset: token.NewFileSet(), 55 ParserMode: parser.ParseComments, 56 Build: &ctx, 57 } 58 59 // Each entry is a single-file package. 60 // (Multi-file packages aren't interesting for this test.) 61 // Order matters: each non-template package is processed using 62 // the preceding template package. 63 for _, filename := range []string{ 64 "testdata/A.template", 65 "testdata/A1.go", 66 "testdata/A2.go", 67 68 "testdata/B.template", 69 "testdata/B1.go", 70 71 "testdata/C.template", 72 "testdata/C1.go", 73 74 "testdata/D.template", 75 "testdata/D1.go", 76 77 "testdata/E.template", 78 "testdata/E1.go", 79 80 "testdata/F.template", 81 "testdata/F1.go", 82 83 "testdata/G.template", 84 "testdata/G1.go", 85 86 "testdata/H.template", 87 "testdata/H1.go", 88 89 "testdata/I.template", 90 "testdata/I1.go", 91 92 "testdata/J.template", 93 "testdata/J1.go", 94 95 "testdata/bad_type.template", 96 "testdata/no_before.template", 97 "testdata/no_after_return.template", 98 "testdata/type_mismatch.template", 99 "testdata/expr_type_mismatch.template", 100 } { 101 pkgname := strings.TrimSuffix(filepath.Base(filename), ".go") 102 conf.CreateFromFilenames(pkgname, filename) 103 } 104 iprog, err := conf.Load() 105 if err != nil { 106 t.Fatal(err) 107 } 108 109 var xform *eg.Transformer 110 for _, info := range iprog.Created { 111 file := info.Files[0] 112 filename := iprog.Fset.File(file.Pos()).Name() // foo.go 113 114 if strings.HasSuffix(filename, "template") { 115 // a new template 116 shouldFail, _ := info.Pkg.Scope().Lookup("shouldFail").(*types.Const) 117 xform, err = eg.NewTransformer(iprog.Fset, info.Pkg, file, &info.Info, *verboseFlag) 118 if err != nil { 119 if shouldFail == nil { 120 t.Errorf("NewTransformer(%s): %s", filename, err) 121 } else if want := constant.StringVal(shouldFail.Val()); !strings.Contains(normalizeAny(err.Error()), want) { 122 t.Errorf("NewTransformer(%s): got error %q, want error %q", filename, err, want) 123 } 124 } else if shouldFail != nil { 125 t.Errorf("NewTransformer(%s) succeeded unexpectedly; want error %q", 126 filename, shouldFail.Val()) 127 } 128 continue 129 } 130 131 if xform == nil { 132 t.Errorf("%s: no previous template", filename) 133 continue 134 } 135 136 // apply previous template to this package 137 n := xform.Transform(&info.Info, info.Pkg, file) 138 if n == 0 { 139 t.Errorf("%s: no matches", filename) 140 continue 141 } 142 143 gotf, err := os.CreateTemp("", filepath.Base(filename)+"t") 144 if err != nil { 145 t.Fatal(err) 146 } 147 got := gotf.Name() // foo.got 148 golden := filename + "lden" // foo.golden 149 150 // Write actual output to foo.got. 151 if err := eg.WriteAST(iprog.Fset, got, file); err != nil { 152 t.Error(err) 153 } 154 defer os.Remove(got) 155 156 // Compare foo.got with foo.golden. 157 var cmd *exec.Cmd 158 switch runtime.GOOS { 159 case "plan9": 160 cmd = exec.Command("/bin/diff", "-c", golden, got) 161 default: 162 cmd = exec.Command("/usr/bin/diff", "-u", golden, got) 163 } 164 buf := new(bytes.Buffer) 165 cmd.Stdout = buf 166 cmd.Stderr = os.Stderr 167 if err := cmd.Run(); err != nil { 168 t.Errorf("eg tests for %s failed: %s.\n%s\n", filename, err, buf) 169 170 if *updateFlag { 171 t.Logf("Updating %s...", golden) 172 if err := exec.Command("/bin/cp", got, golden).Run(); err != nil { 173 t.Errorf("Update failed: %s", err) 174 } 175 } 176 } 177 } 178 } 179 180 // normalizeAny replaces occurrences of interface{} with any, for consistent 181 // output. 182 func normalizeAny(s string) string { 183 return strings.ReplaceAll(s, "interface{}", "any") 184 }