| // Copyright 2014 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package main | |
| import ( | |
| "debug/goobj" | |
| "reflect" | |
| "strings" | |
| "testing" | |
| ) | |
| // Each test case is an object file, generated from a corresponding .s file. | |
| // The symbols in the object file with a dead_ prefix are the ones that | |
| // should be removed from the program. | |
| var deadTests = []string{ | |
| "testdata/dead.6", | |
| } | |
| func TestDead(t *testing.T) { | |
| for _, obj := range deadTests { | |
| p := Prog{GOOS: "darwin", GOARCH: "amd64", StartSym: "start"} | |
| p.omitRuntime = true | |
| p.Error = func(s string) { t.Error(s) } | |
| p.init() | |
| p.scan(obj) | |
| if p.NumError > 0 { | |
| continue // already reported | |
| } | |
| origSyms := copyMap(p.Syms) | |
| origMissing := copyMap(p.Missing) | |
| origSymOrder := copySlice(p.SymOrder) | |
| origPkgSyms := copySlice(p.Packages["main"].Syms) | |
| p.dead() | |
| checkDeadMap(t, obj, "p.Syms", origSyms, p.Syms) | |
| checkDeadMap(t, obj, "p.Missing", origMissing, p.Missing) | |
| checkDeadSlice(t, obj, "p.SymOrder", origSymOrder, p.SymOrder) | |
| checkDeadSlice(t, obj, `p.Packages["main"].Syms`, origPkgSyms, p.Packages["main"].Syms) | |
| } | |
| } | |
| func copyMap(m interface{}) interface{} { | |
| v := reflect.ValueOf(m) | |
| out := reflect.MakeMap(v.Type()) | |
| for _, key := range v.MapKeys() { | |
| out.SetMapIndex(key, v.MapIndex(key)) | |
| } | |
| return out.Interface() | |
| } | |
| func checkDeadMap(t *testing.T, obj, name string, old, new interface{}) { | |
| vold := reflect.ValueOf(old) | |
| vnew := reflect.ValueOf(new) | |
| for _, vid := range vold.MapKeys() { | |
| id := vid.Interface().(goobj.SymID) | |
| if strings.HasPrefix(id.Name, "dead_") { | |
| if vnew.MapIndex(vid).IsValid() { | |
| t.Errorf("%s: %s contains unnecessary symbol %s", obj, name, id) | |
| } | |
| } else { | |
| if !vnew.MapIndex(vid).IsValid() { | |
| t.Errorf("%s: %s is missing symbol %s", obj, name, id) | |
| } | |
| } | |
| } | |
| for _, vid := range vnew.MapKeys() { | |
| id := vid.Interface().(goobj.SymID) | |
| if !vold.MapIndex(vid).IsValid() { | |
| t.Errorf("%s: %s contains unexpected symbol %s", obj, name, id) | |
| } | |
| } | |
| } | |
| func copySlice(x []*Sym) (out []*Sym) { | |
| return append(out, x...) | |
| } | |
| func checkDeadSlice(t *testing.T, obj, name string, old, new []*Sym) { | |
| for i, s := range old { | |
| if strings.HasPrefix(s.Name, "dead_") { | |
| continue | |
| } | |
| if len(new) == 0 { | |
| t.Errorf("%s: %s is missing symbol %s\nhave%v\nwant%v", obj, name, s, new, old[i:]) | |
| return | |
| } | |
| if new[0].SymID != s.SymID { | |
| t.Errorf("%s: %s is incorrect: have %s, want %s\nhave%v\nwant%v", obj, name, new[0].SymID, s.SymID, new, old[i:]) | |
| return | |
| } | |
| new = new[1:] | |
| } | |
| if len(new) > 0 { | |
| t.Errorf("%s: %s has unexpected symbols: %v", obj, name, new) | |
| } | |
| } |