github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/internal/goobj/goobj_test.go (about) 1 // Copyright 2017 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 goobj 6 7 import ( 8 "debug/elf" 9 "debug/macho" 10 "debug/pe" 11 "fmt" 12 "internal/testenv" 13 "io" 14 "io/ioutil" 15 "os" 16 "os/exec" 17 "path/filepath" 18 "runtime" 19 "testing" 20 ) 21 22 var ( 23 buildDir string 24 go1obj string 25 go2obj string 26 goarchive string 27 cgoarchive string 28 ) 29 30 func TestMain(m *testing.M) { 31 if !testenv.HasGoBuild() { 32 return 33 } 34 35 if err := buildGoobj(); err != nil { 36 fmt.Println(err) 37 os.RemoveAll(buildDir) 38 os.Exit(1) 39 } 40 41 exit := m.Run() 42 43 os.RemoveAll(buildDir) 44 os.Exit(exit) 45 } 46 47 func copyDir(dst, src string) error { 48 err := os.MkdirAll(dst, 0777) 49 if err != nil { 50 return err 51 } 52 fis, err := ioutil.ReadDir(src) 53 if err != nil { 54 return err 55 } 56 for _, fi := range fis { 57 err = copyFile(filepath.Join(dst, fi.Name()), filepath.Join(src, fi.Name())) 58 if err != nil { 59 return err 60 } 61 } 62 return nil 63 } 64 65 func copyFile(dst, src string) (err error) { 66 var s, d *os.File 67 s, err = os.Open(src) 68 if err != nil { 69 return err 70 } 71 defer s.Close() 72 d, err = os.Create(dst) 73 if err != nil { 74 return err 75 } 76 defer func() { 77 e := d.Close() 78 if err == nil { 79 err = e 80 } 81 }() 82 _, err = io.Copy(d, s) 83 if err != nil { 84 return err 85 } 86 return nil 87 } 88 89 func buildGoobj() error { 90 var err error 91 92 buildDir, err = ioutil.TempDir("", "TestGoobj") 93 if err != nil { 94 return err 95 } 96 97 go1obj = filepath.Join(buildDir, "go1.o") 98 go2obj = filepath.Join(buildDir, "go2.o") 99 goarchive = filepath.Join(buildDir, "go.a") 100 101 gotool, err := testenv.GoTool() 102 if err != nil { 103 return err 104 } 105 106 go1src := filepath.Join("testdata", "go1.go") 107 go2src := filepath.Join("testdata", "go2.go") 108 109 out, err := exec.Command(gotool, "tool", "compile", "-o", go1obj, go1src).CombinedOutput() 110 if err != nil { 111 return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go1obj, go1src, err, out) 112 } 113 out, err = exec.Command(gotool, "tool", "compile", "-o", go2obj, go2src).CombinedOutput() 114 if err != nil { 115 return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go2obj, go2src, err, out) 116 } 117 out, err = exec.Command(gotool, "tool", "pack", "c", goarchive, go1obj, go2obj).CombinedOutput() 118 if err != nil { 119 return fmt.Errorf("go tool pack c %s %s %s: %v\n%s", goarchive, go1obj, go2obj, err, out) 120 } 121 122 if testenv.HasCGO() { 123 gopath := filepath.Join(buildDir, "gopath") 124 err = copyDir(filepath.Join(gopath, "src", "mycgo"), filepath.Join("testdata", "mycgo")) 125 if err != nil { 126 return err 127 } 128 cmd := exec.Command(gotool, "install", "-gcflags=all="+os.Getenv("GO_GCFLAGS"), "mycgo") 129 cmd.Env = append(os.Environ(), "GOPATH="+gopath) 130 out, err = cmd.CombinedOutput() 131 if err != nil { 132 return fmt.Errorf("go install mycgo: %v\n%s", err, out) 133 } 134 pat := filepath.Join(gopath, "pkg", "*", "mycgo.a") 135 ms, err := filepath.Glob(pat) 136 if err != nil { 137 return err 138 } 139 if len(ms) == 0 { 140 return fmt.Errorf("cannot found paths for pattern %s", pat) 141 } 142 cgoarchive = ms[0] 143 } 144 145 return nil 146 } 147 148 func TestParseGoobj(t *testing.T) { 149 path := go1obj 150 151 f, err := os.Open(path) 152 if err != nil { 153 t.Fatal(err) 154 } 155 defer f.Close() 156 157 p, err := Parse(f, "mypkg") 158 if err != nil { 159 t.Fatal(err) 160 } 161 if p.Arch != runtime.GOARCH { 162 t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) 163 } 164 var found bool 165 for _, s := range p.Syms { 166 if s.Name == "mypkg.go1" { 167 found = true 168 break 169 } 170 } 171 if !found { 172 t.Errorf(`%s: symbol "mypkg.go1" not found`, path) 173 } 174 } 175 176 func TestParseArchive(t *testing.T) { 177 path := goarchive 178 179 f, err := os.Open(path) 180 if err != nil { 181 t.Fatal(err) 182 } 183 defer f.Close() 184 185 p, err := Parse(f, "mypkg") 186 if err != nil { 187 t.Fatal(err) 188 } 189 if p.Arch != runtime.GOARCH { 190 t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) 191 } 192 var found1 bool 193 var found2 bool 194 for _, s := range p.Syms { 195 if s.Name == "mypkg.go1" { 196 found1 = true 197 } 198 if s.Name == "mypkg.go2" { 199 found2 = true 200 } 201 } 202 if !found1 { 203 t.Errorf(`%s: symbol "mypkg.go1" not found`, path) 204 } 205 if !found2 { 206 t.Errorf(`%s: symbol "mypkg.go2" not found`, path) 207 } 208 } 209 210 func TestParseCGOArchive(t *testing.T) { 211 testenv.MustHaveCGO(t) 212 213 path := cgoarchive 214 215 f, err := os.Open(path) 216 if err != nil { 217 t.Fatal(err) 218 } 219 defer f.Close() 220 221 p, err := Parse(f, "mycgo") 222 if err != nil { 223 t.Fatal(err) 224 } 225 if p.Arch != runtime.GOARCH { 226 t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) 227 } 228 var found1 bool 229 var found2 bool 230 for _, s := range p.Syms { 231 if s.Name == "mycgo.go1" { 232 found1 = true 233 } 234 if s.Name == "mycgo.go2" { 235 found2 = true 236 } 237 } 238 if !found1 { 239 t.Errorf(`%s: symbol "mycgo.go1" not found`, path) 240 } 241 if !found2 { 242 t.Errorf(`%s: symbol "mycgo.go2" not found`, path) 243 } 244 245 c1 := "c1" 246 c2 := "c2" 247 248 found1 = false 249 found2 = false 250 251 switch runtime.GOOS { 252 case "darwin": 253 c1 = "_" + c1 254 c2 = "_" + c2 255 for _, obj := range p.Native { 256 mf, err := macho.NewFile(obj) 257 if err != nil { 258 t.Fatal(err) 259 } 260 if mf.Symtab == nil { 261 continue 262 } 263 for _, s := range mf.Symtab.Syms { 264 switch s.Name { 265 case c1: 266 found1 = true 267 case c2: 268 found2 = true 269 } 270 } 271 } 272 case "windows": 273 if runtime.GOARCH == "386" { 274 c1 = "_" + c1 275 c2 = "_" + c2 276 } 277 for _, obj := range p.Native { 278 pf, err := pe.NewFile(obj) 279 if err != nil { 280 t.Fatal(err) 281 } 282 for _, s := range pf.Symbols { 283 switch s.Name { 284 case c1: 285 found1 = true 286 case c2: 287 found2 = true 288 } 289 } 290 } 291 default: 292 for _, obj := range p.Native { 293 ef, err := elf.NewFile(obj) 294 if err != nil { 295 t.Fatal(err) 296 } 297 syms, err := ef.Symbols() 298 if err != nil { 299 t.Fatal(err) 300 } 301 for _, s := range syms { 302 switch s.Name { 303 case c1: 304 found1 = true 305 case c2: 306 found2 = true 307 } 308 } 309 } 310 } 311 312 if !found1 { 313 t.Errorf(`%s: symbol %q not found`, path, c1) 314 } 315 if !found2 { 316 t.Errorf(`%s: symbol %q not found`, path, c2) 317 } 318 }