.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / go / callgraph / rta / rta_test.go
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 //lint:file-ignore SA1019 go/callgraph's test suite is built around the deprecated go/loader. We'll leave fixing that to upstream.
6
7 // No testdata on Android.
8
9 // +build !android
10
11 package rta_test
12
13 import (
14         "bytes"
15         "fmt"
16         "go/ast"
17         "go/parser"
18         "go/token"
19         "go/types"
20         "io/ioutil"
21         "sort"
22         "strings"
23         "testing"
24
25         "honnef.co/go/tools/go/callgraph"
26         "honnef.co/go/tools/go/callgraph/rta"
27         "honnef.co/go/tools/go/ir"
28         "honnef.co/go/tools/go/ir/irutil"
29
30         "golang.org/x/tools/go/loader"
31 )
32
33 var inputs = []string{
34         "testdata/func.go",
35         "testdata/rtype.go",
36         "testdata/iface.go",
37 }
38
39 func expectation(f *ast.File) (string, token.Pos) {
40         for _, c := range f.Comments {
41                 text := strings.TrimSpace(c.Text())
42                 if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
43                         return t, c.Pos()
44                 }
45         }
46         return "", token.NoPos
47 }
48
49 // TestRTA runs RTA on each file in inputs, prints the results, and
50 // compares it with the golden results embedded in the WANT comment at
51 // the end of the file.
52 //
53 // The results string consists of two parts: the set of dynamic call
54 // edges, "f --> g", one per line, and the set of reachable functions,
55 // one per line.  Each set is sorted.
56 //
57 func TestRTA(t *testing.T) {
58         for _, filename := range inputs {
59                 content, err := ioutil.ReadFile(filename)
60                 if err != nil {
61                         t.Errorf("couldn't read file '%s': %s", filename, err)
62                         continue
63                 }
64
65                 conf := loader.Config{
66                         ParserMode: parser.ParseComments,
67                 }
68                 f, err := conf.ParseFile(filename, content)
69                 if err != nil {
70                         t.Error(err)
71                         continue
72                 }
73
74                 want, pos := expectation(f)
75                 if pos == token.NoPos {
76                         t.Errorf("No WANT: comment in %s", filename)
77                         continue
78                 }
79
80                 conf.CreateFromFiles("main", f)
81                 iprog, err := conf.Load()
82                 if err != nil {
83                         t.Error(err)
84                         continue
85                 }
86
87                 prog := irutil.CreateProgram(iprog, 0)
88                 mainPkg := prog.Package(iprog.Created[0].Pkg)
89                 prog.Build()
90
91                 res := rta.Analyze([]*ir.Function{
92                         mainPkg.Func("main"),
93                         mainPkg.Func("init"),
94                 }, true)
95
96                 if got := printResult(res, mainPkg.Pkg); got != want {
97                         t.Errorf("%s: got:\n%s\nwant:\n%s",
98                                 prog.Fset.Position(pos), got, want)
99                 }
100         }
101 }
102
103 func printResult(res *rta.Result, from *types.Package) string {
104         var buf bytes.Buffer
105
106         writeSorted := func(ss []string) {
107                 sort.Strings(ss)
108                 for _, s := range ss {
109                         fmt.Fprintf(&buf, "  %s\n", s)
110                 }
111         }
112
113         buf.WriteString("Dynamic calls\n")
114         var edges []string
115         callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error {
116                 if strings.Contains(e.Description(), "dynamic") {
117                         edges = append(edges, fmt.Sprintf("%s --> %s",
118                                 e.Caller.Func.RelString(from),
119                                 e.Callee.Func.RelString(from)))
120                 }
121                 return nil
122         })
123         writeSorted(edges)
124
125         buf.WriteString("Reachable functions\n")
126         var reachable []string
127         for f := range res.Reachable {
128                 reachable = append(reachable, f.RelString(from))
129         }
130         writeSorted(reachable)
131
132         buf.WriteString("Reflect types\n")
133         var rtypes []string
134         res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
135                 if value == false { // accessible to reflection
136                         rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
137                 }
138         })
139         writeSorted(rtypes)
140
141         return strings.TrimSpace(buf.String())
142 }