github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/go/callgraph/cha/cha_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 cha_test 11 12 import ( 13 "bytes" 14 "fmt" 15 "go/ast" 16 "go/parser" 17 "go/token" 18 "go/types" 19 "io/ioutil" 20 "sort" 21 "strings" 22 "testing" 23 24 "github.com/jhump/golang-x-tools/go/callgraph" 25 "github.com/jhump/golang-x-tools/go/callgraph/cha" 26 "github.com/jhump/golang-x-tools/go/loader" 27 "github.com/jhump/golang-x-tools/go/ssa/ssautil" 28 ) 29 30 var inputs = []string{ 31 "testdata/func.go", 32 "testdata/iface.go", 33 "testdata/recv.go", 34 "testdata/issue23925.go", 35 } 36 37 func expectation(f *ast.File) (string, token.Pos) { 38 for _, c := range f.Comments { 39 text := strings.TrimSpace(c.Text()) 40 if t := strings.TrimPrefix(text, "WANT:\n"); t != text { 41 return t, c.Pos() 42 } 43 } 44 return "", token.NoPos 45 } 46 47 // TestCHA runs CHA on each file in inputs, prints the dynamic edges of 48 // the call graph, and compares it with the golden results embedded in 49 // the WANT comment at the end of the file. 50 // 51 func TestCHA(t *testing.T) { 52 for _, filename := range inputs { 53 content, err := ioutil.ReadFile(filename) 54 if err != nil { 55 t.Errorf("couldn't read file '%s': %s", filename, err) 56 continue 57 } 58 59 conf := loader.Config{ 60 ParserMode: parser.ParseComments, 61 } 62 f, err := conf.ParseFile(filename, content) 63 if err != nil { 64 t.Error(err) 65 continue 66 } 67 68 want, pos := expectation(f) 69 if pos == token.NoPos { 70 t.Errorf("No WANT: comment in %s", filename) 71 continue 72 } 73 74 conf.CreateFromFiles("main", f) 75 iprog, err := conf.Load() 76 if err != nil { 77 t.Error(err) 78 continue 79 } 80 81 prog := ssautil.CreateProgram(iprog, 0) 82 mainPkg := prog.Package(iprog.Created[0].Pkg) 83 prog.Build() 84 85 cg := cha.CallGraph(prog) 86 87 if got := printGraph(cg, mainPkg.Pkg); got != want { 88 t.Errorf("%s: got:\n%s\nwant:\n%s", 89 prog.Fset.Position(pos), got, want) 90 } 91 } 92 } 93 94 func printGraph(cg *callgraph.Graph, from *types.Package) string { 95 var edges []string 96 callgraph.GraphVisitEdges(cg, func(e *callgraph.Edge) error { 97 if strings.Contains(e.Description(), "dynamic") { 98 edges = append(edges, fmt.Sprintf("%s --> %s", 99 e.Caller.Func.RelString(from), 100 e.Callee.Func.RelString(from))) 101 } 102 return nil 103 }) 104 sort.Strings(edges) 105 106 var buf bytes.Buffer 107 buf.WriteString("Dynamic calls\n") 108 for _, edge := range edges { 109 fmt.Fprintf(&buf, " %s\n", edge) 110 } 111 return strings.TrimSpace(buf.String()) 112 }