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  }