github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/callgraph/vta/vta_test.go (about) 1 // Copyright 2021 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 vta 6 7 import ( 8 "testing" 9 10 "github.com/powerman/golang-tools/go/analysis" 11 "github.com/powerman/golang-tools/go/analysis/analysistest" 12 "github.com/powerman/golang-tools/go/analysis/passes/buildssa" 13 "github.com/powerman/golang-tools/go/callgraph/cha" 14 "github.com/powerman/golang-tools/go/ssa" 15 "github.com/powerman/golang-tools/go/ssa/ssautil" 16 ) 17 18 func TestVTACallGraph(t *testing.T) { 19 for _, file := range []string{ 20 "testdata/src/callgraph_static.go", 21 "testdata/src/callgraph_ho.go", 22 "testdata/src/callgraph_interfaces.go", 23 "testdata/src/callgraph_pointers.go", 24 "testdata/src/callgraph_collections.go", 25 "testdata/src/callgraph_fields.go", 26 "testdata/src/callgraph_field_funcs.go", 27 } { 28 t.Run(file, func(t *testing.T) { 29 prog, want, err := testProg(file) 30 if err != nil { 31 t.Fatalf("couldn't load test file '%s': %s", file, err) 32 } 33 if len(want) == 0 { 34 t.Fatalf("couldn't find want in `%s`", file) 35 } 36 37 g := CallGraph(ssautil.AllFunctions(prog), cha.CallGraph(prog)) 38 if got := callGraphStr(g); !subGraph(want, got) { 39 t.Errorf("computed callgraph %v should contain %v", got, want) 40 } 41 }) 42 } 43 } 44 45 // TestVTAProgVsFuncSet exemplifies and tests different possibilities 46 // enabled by having an arbitrary function set as input to CallGraph 47 // instead of the whole program (i.e., ssautil.AllFunctions(prog)). 48 func TestVTAProgVsFuncSet(t *testing.T) { 49 prog, want, err := testProg("testdata/src/callgraph_nested_ptr.go") 50 if err != nil { 51 t.Fatalf("couldn't load test `testdata/src/callgraph_nested_ptr.go`: %s", err) 52 } 53 if len(want) == 0 { 54 t.Fatal("couldn't find want in `testdata/src/callgraph_nested_ptr.go`") 55 } 56 57 allFuncs := ssautil.AllFunctions(prog) 58 g := CallGraph(allFuncs, cha.CallGraph(prog)) 59 // VTA over the whole program will produce a call graph that 60 // includes Baz:(**i).Foo -> A.Foo, B.Foo. 61 if got := callGraphStr(g); !subGraph(want, got) { 62 t.Errorf("computed callgraph %v should contain %v", got, want) 63 } 64 65 // Prune the set of program functions to exclude Bar(). This should 66 // yield a call graph that includes different set of callees for Baz 67 // Baz:(**i).Foo -> A.Foo 68 // 69 // Note that the exclusion of Bar can happen, for instance, if Baz is 70 // considered an entry point of some data flow analysis and Bar is 71 // provably (e.g., using CHA forward reachability) unreachable from Baz. 72 noBarFuncs := make(map[*ssa.Function]bool) 73 for f, in := range allFuncs { 74 noBarFuncs[f] = in && (funcName(f) != "Bar") 75 } 76 want = []string{"Baz: Do(i) -> Do; invoke t2.Foo() -> A.Foo"} 77 g = CallGraph(noBarFuncs, cha.CallGraph(prog)) 78 if got := callGraphStr(g); !subGraph(want, got) { 79 t.Errorf("pruned callgraph %v should contain %v", got, want) 80 } 81 } 82 83 // TestVTAPanicMissingDefinitions tests if VTA gracefully handles the case 84 // where VTA panics when a definition of a function or method is not 85 // available, which can happen when using analysis package. A successful 86 // test simply does not panic. 87 func TestVTAPanicMissingDefinitions(t *testing.T) { 88 run := func(pass *analysis.Pass) (interface{}, error) { 89 s := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA) 90 CallGraph(ssautil.AllFunctions(s.Pkg.Prog), cha.CallGraph(s.Pkg.Prog)) 91 return nil, nil 92 } 93 94 analyzer := &analysis.Analyzer{ 95 Name: "test", 96 Doc: "test", 97 Run: run, 98 Requires: []*analysis.Analyzer{ 99 buildssa.Analyzer, 100 }, 101 } 102 103 testdata := analysistest.TestData() 104 res := analysistest.Run(t, testdata, analyzer, "t", "d") 105 if len(res) != 2 { 106 t.Errorf("want analysis results for 2 packages; got %v", len(res)) 107 } 108 for _, r := range res { 109 if r.Err != nil { 110 t.Errorf("want no error for package %v; got %v", r.Pass.Pkg.Path(), r.Err) 111 } 112 } 113 }