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