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