github.com/jujuyuki/gospal@v1.0.1-0.20210215170718-af79fae13b20/ssa/ssa_test.go (about) 1 package ssa_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "strings" 8 "testing" 9 10 "github.com/jujuyuki/gospal/ssa" 11 "github.com/jujuyuki/gospal/ssa/build" 12 ) 13 14 // This tests basic build. 15 func TestBuild(t *testing.T) { 16 s := `package main 17 import "fmt" 18 func main() { 19 fmt.Println("Hello World") 20 }` 21 22 conf := build.FromReader(strings.NewReader(s)) 23 info, err := conf.Build() 24 if err != nil { 25 t.Errorf("SSA build failed: %v", err) 26 } 27 if info.Prog == nil { 28 t.Errorf("SSA Program missing") 29 } 30 mains, err := ssa.MainPkgs(info.Prog, false) 31 if err != nil { 32 t.Errorf("cannot find main packages: %v", err) 33 } 34 for _, main := range mains { 35 if main.Func("main") == nil { 36 t.Error("expects main.main() but not found") 37 } 38 } 39 } 40 41 // This tests building with non-main package. 42 func TestBuildNonMainPkg(t *testing.T) { 43 s := `package pkg 44 import "fmt" 45 func main() { 46 fmt.Println("Hello World") 47 }` 48 49 conf := build.FromReader(strings.NewReader(s)) 50 info, err := conf.Build() 51 if _, err = ssa.MainPkgs(info.Prog, false); err != ssa.ErrNoMainPkgs { 52 t.Errorf("unexpected main package") 53 } 54 } 55 56 // This tests building of callgraph. 57 func TestCallGraph(t *testing.T) { 58 s := `package main 59 import "fmt" 60 func main() { 61 foo("Hello") 62 } 63 func foo(s string) { 64 fmt.Println(s, "World") 65 } 66 func bar() { 67 fmt.Println("doesn't reach here") 68 }` 69 70 conf := build.FromReader(strings.NewReader(s)) 71 info, err := conf.Build() 72 if err != nil { 73 t.Errorf("SSA build failed: %v", err) 74 } 75 if info.Prog == nil { 76 t.Errorf("SSA Program missing") 77 } 78 mains, err := ssa.MainPkgs(info.Prog, false) 79 if err != nil { 80 t.Errorf("cannot find main packages: %v", err) 81 } 82 for _, main := range mains { 83 if main.Func("main") == nil { 84 t.Error("expects main.main() but not found") 85 } 86 } 87 graph, err := info.BuildCallGraph("pta", false) 88 if err != nil { 89 t.Errorf("build callgraph failed: %v", err) 90 } 91 fns, err := graph.UsedFunctions() 92 if err != nil { 93 t.Errorf("cannot filter unused functions in callgraph: %v", err) 94 } 95 for _, fn := range fns { 96 if fn.Pkg.Pkg.Name() == "main" { 97 if fn.Name() != "foo" && fn.Name() != "main" && fn.Name() != "init" { 98 t.Errorf("expecting main.{init, main, foo}, but got main.%s", fn.Name()) 99 } 100 } 101 } 102 } 103 104 // This tests building of callgraph and retrieving of all functions in callgraph. 105 func TestCallGraphAllFunc(t *testing.T) { 106 s := `package main 107 import "fmt" 108 func main() { 109 foo("Hello") 110 } 111 func foo(s string) { 112 fmt.Println(s, "World") 113 } 114 func bar() { 115 fmt.Println("doesn't reach here") 116 }` 117 118 conf := build.FromReader(strings.NewReader(s)) 119 info, err := conf.Build() 120 if err != nil { 121 t.Errorf("SSA build failed: %v", err) 122 } 123 if info.Prog == nil { 124 t.Errorf("SSA Program missing") 125 } 126 mains, err := ssa.MainPkgs(info.Prog, false) 127 if err != nil { 128 t.Errorf("cannot find main packages: %v", err) 129 } 130 for _, main := range mains { 131 if main.Func("main") == nil { 132 t.Error("expects main.main() but not found") 133 } 134 } 135 graph, err := info.BuildCallGraph("pta", false) 136 if err != nil { 137 t.Errorf("build callgraph failed: %v", err) 138 } 139 140 allFuncs, err := graph.AllFunctions() 141 if err != nil { 142 t.Errorf("cannot get functions in callgraph: %v", err) 143 } 144 usedFuncs, err := graph.UsedFunctions() 145 if err != nil { 146 t.Errorf("cannot filter unused functions in callgraph: %v", err) 147 } 148 if len(allFuncs) < len(usedFuncs) { 149 t.Errorf("callgraph has %d functions, %d are used. Expect used < all", 150 len(allFuncs), len(usedFuncs)) 151 } 152 } 153 154 func ExampleInfo_WriteTo() { 155 s := `package main 156 func main() { }` 157 158 conf := build.FromReader(strings.NewReader(s)) 159 info, err := conf.Build() 160 if err != nil { 161 log.Fatalf("SSA build failed: %v", err) 162 } 163 var buf bytes.Buffer 164 info.WriteTo(&buf) 165 fmt.Println(buf.String()) 166 // output: 167 // # Name: main.init 168 // # Package: main 169 // # Synthetic: package initializer 170 // func init(): 171 // 0: entry P:0 S:0 172 // return 173 // 174 // # Name: main.main 175 // # Package: main 176 // # Location: tmp:2:7 177 // func main(): 178 // 0: entry P:0 S:0 179 // return 180 } 181 182 func ExampleCallGraph_WriteGraphviz() { 183 s := `package main 184 func main() { }` 185 186 conf := build.FromReader(strings.NewReader(s)) 187 info, err := conf.Build() 188 if err != nil { 189 log.Fatalf("SSA build failed: %v", err) 190 } 191 var buf bytes.Buffer 192 cg, err := info.BuildCallGraph("pta", false) // Pointer analysis, no tests. 193 if err != nil { 194 log.Fatalf("Cannot build callgraph: %v", err) 195 } 196 cg.WriteGraphviz(&buf) 197 fmt.Println(buf.String()) 198 // output: 199 // digraph callgraph { 200 // "<root>" -> "main.init" 201 // "<root>" -> "main.main" 202 // } 203 }