github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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/constant" 16 "go/parser" 17 "go/token" 18 "go/types" 19 "io/ioutil" 20 "os" 21 "os/exec" 22 "path/filepath" 23 "runtime" 24 "strings" 25 "testing" 26 27 "github.com/powerman/golang-tools/go/loader" 28 "github.com/powerman/golang-tools/internal/testenv" 29 "github.com/powerman/golang-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 conf := loader.Config{ 52 Fset: token.NewFileSet(), 53 ParserMode: parser.ParseComments, 54 } 55 56 // Each entry is a single-file package. 57 // (Multi-file packages aren't interesting for this test.) 58 // Order matters: each non-template package is processed using 59 // the preceding template package. 60 for _, filename := range []string{ 61 "testdata/A.template", 62 "testdata/A1.go", 63 "testdata/A2.go", 64 65 "testdata/B.template", 66 "testdata/B1.go", 67 68 "testdata/C.template", 69 "testdata/C1.go", 70 71 "testdata/D.template", 72 "testdata/D1.go", 73 74 "testdata/E.template", 75 "testdata/E1.go", 76 77 "testdata/F.template", 78 "testdata/F1.go", 79 80 "testdata/G.template", 81 "testdata/G1.go", 82 83 "testdata/H.template", 84 "testdata/H1.go", 85 86 "testdata/I.template", 87 "testdata/I1.go", 88 89 "testdata/J.template", 90 "testdata/J1.go", 91 92 "testdata/bad_type.template", 93 "testdata/no_before.template", 94 "testdata/no_after_return.template", 95 "testdata/type_mismatch.template", 96 "testdata/expr_type_mismatch.template", 97 } { 98 pkgname := strings.TrimSuffix(filepath.Base(filename), ".go") 99 conf.CreateFromFilenames(pkgname, filename) 100 } 101 iprog, err := conf.Load() 102 if err != nil { 103 t.Fatal(err) 104 } 105 106 var xform *eg.Transformer 107 for _, info := range iprog.Created { 108 file := info.Files[0] 109 filename := iprog.Fset.File(file.Pos()).Name() // foo.go 110 111 if strings.HasSuffix(filename, "template") { 112 // a new template 113 shouldFail, _ := info.Pkg.Scope().Lookup("shouldFail").(*types.Const) 114 xform, err = eg.NewTransformer(iprog.Fset, info.Pkg, file, &info.Info, *verboseFlag) 115 if err != nil { 116 if shouldFail == nil { 117 t.Errorf("NewTransformer(%s): %s", filename, err) 118 } else if want := constant.StringVal(shouldFail.Val()); !strings.Contains(normalizeAny(err.Error()), want) { 119 t.Errorf("NewTransformer(%s): got error %q, want error %q", filename, err, want) 120 } 121 } else if shouldFail != nil { 122 t.Errorf("NewTransformer(%s) succeeded unexpectedly; want error %q", 123 filename, shouldFail.Val()) 124 } 125 continue 126 } 127 128 if xform == nil { 129 t.Errorf("%s: no previous template", filename) 130 continue 131 } 132 133 // apply previous template to this package 134 n := xform.Transform(&info.Info, info.Pkg, file) 135 if n == 0 { 136 t.Errorf("%s: no matches", filename) 137 continue 138 } 139 140 gotf, err := ioutil.TempFile("", filepath.Base(filename)+"t") 141 if err != nil { 142 t.Fatal(err) 143 } 144 got := gotf.Name() // foo.got 145 golden := filename + "lden" // foo.golden 146 147 // Write actual output to foo.got. 148 if err := eg.WriteAST(iprog.Fset, got, file); err != nil { 149 t.Error(err) 150 } 151 defer os.Remove(got) 152 153 // Compare foo.got with foo.golden. 154 var cmd *exec.Cmd 155 switch runtime.GOOS { 156 case "plan9": 157 cmd = exec.Command("/bin/diff", "-c", golden, got) 158 default: 159 cmd = exec.Command("/usr/bin/diff", "-u", golden, got) 160 } 161 buf := new(bytes.Buffer) 162 cmd.Stdout = buf 163 cmd.Stderr = os.Stderr 164 if err := cmd.Run(); err != nil { 165 t.Errorf("eg tests for %s failed: %s.\n%s\n", filename, err, buf) 166 167 if *updateFlag { 168 t.Logf("Updating %s...", golden) 169 if err := exec.Command("/bin/cp", got, golden).Run(); err != nil { 170 t.Errorf("Update failed: %s", err) 171 } 172 } 173 } 174 } 175 } 176 177 // normalizeAny replaces occurrences of interface{} with any, for consistent 178 // output. 179 func normalizeAny(s string) string { 180 return strings.ReplaceAll(s, "interface{}", "any") 181 }