github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/cmd/nm/nm_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 main
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"fmt"
    11  	"internal/testenv"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"runtime"
    17  	"strings"
    18  	"testing"
    19  	"text/template"
    20  )
    21  
    22  var testnmpath string // path to nm command created for testing purposes
    23  
    24  // The TestMain function creates a nm command for testing purposes and
    25  // deletes it after the tests have been run.
    26  func TestMain(m *testing.M) {
    27  	os.Exit(testMain(m))
    28  }
    29  
    30  func testMain(m *testing.M) int {
    31  	if !testenv.HasGoBuild() {
    32  		return 0
    33  	}
    34  
    35  	tmpDir, err := ioutil.TempDir("", "TestNM")
    36  	if err != nil {
    37  		fmt.Println("TempDir failed:", err)
    38  		return 2
    39  	}
    40  	defer os.RemoveAll(tmpDir)
    41  
    42  	testnmpath = filepath.Join(tmpDir, "testnm.exe")
    43  	gotool, err := testenv.GoTool()
    44  	if err != nil {
    45  		fmt.Println("GoTool failed:", err)
    46  		return 2
    47  	}
    48  	out, err := exec.Command(gotool, "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
    49  	if err != nil {
    50  		fmt.Printf("go build -o %v cmd/nm: %v\n%s", testnmpath, err, string(out))
    51  		return 2
    52  	}
    53  
    54  	return m.Run()
    55  }
    56  
    57  func TestNonGoFiles(t *testing.T) {
    58  	testfiles := []string{
    59  		"elf/testdata/gcc-386-freebsd-exec",
    60  		"elf/testdata/gcc-amd64-linux-exec",
    61  		"macho/testdata/gcc-386-darwin-exec",
    62  		"macho/testdata/gcc-amd64-darwin-exec",
    63  		// "pe/testdata/gcc-amd64-mingw-exec", // no symbols!
    64  		"pe/testdata/gcc-386-mingw-exec",
    65  		"plan9obj/testdata/amd64-plan9-exec",
    66  		"plan9obj/testdata/386-plan9-exec",
    67  	}
    68  	for _, f := range testfiles {
    69  		exepath := filepath.Join(runtime.GOROOT(), "src", "debug", f)
    70  		cmd := exec.Command(testnmpath, exepath)
    71  		out, err := cmd.CombinedOutput()
    72  		if err != nil {
    73  			t.Errorf("go tool nm %v: %v\n%s", exepath, err, string(out))
    74  		}
    75  	}
    76  }
    77  
    78  func testGoFile(t *testing.T, iscgo, isexternallinker bool) {
    79  	tmpdir, err := ioutil.TempDir("", "TestGoFile")
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	defer os.RemoveAll(tmpdir)
    84  
    85  	src := filepath.Join(tmpdir, "a.go")
    86  	file, err := os.Create(src)
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	err = template.Must(template.New("main").Parse(testprog)).Execute(file, iscgo)
    91  	if err != nil {
    92  		file.Close()
    93  		t.Fatal(err)
    94  	}
    95  	file.Close()
    96  
    97  	exe := filepath.Join(tmpdir, "a.exe")
    98  	args := []string{"build", "-o", exe}
    99  	if iscgo {
   100  		linkmode := "internal"
   101  		if isexternallinker {
   102  			linkmode = "external"
   103  		}
   104  		args = append(args, "-ldflags", "-linkmode="+linkmode)
   105  	}
   106  	args = append(args, src)
   107  	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
   108  	if err != nil {
   109  		t.Fatalf("building test executable failed: %s %s", err, out)
   110  	}
   111  
   112  	out, err = exec.Command(exe).CombinedOutput()
   113  	if err != nil {
   114  		t.Fatalf("running test executable failed: %s %s", err, out)
   115  	}
   116  	names := make(map[string]string)
   117  	for _, line := range strings.Split(string(out), "\n") {
   118  		if line == "" {
   119  			continue
   120  		}
   121  		f := strings.Split(line, "=")
   122  		if len(f) != 2 {
   123  			t.Fatalf("unexpected output line: %q", line)
   124  		}
   125  		names["main."+f[0]] = f[1]
   126  	}
   127  
   128  	out, err = exec.Command(testnmpath, exe).CombinedOutput()
   129  	if err != nil {
   130  		t.Fatalf("go tool nm: %v\n%s", err, string(out))
   131  	}
   132  	scanner := bufio.NewScanner(bytes.NewBuffer(out))
   133  	dups := make(map[string]bool)
   134  	for scanner.Scan() {
   135  		f := strings.Fields(scanner.Text())
   136  		if len(f) < 3 {
   137  			continue
   138  		}
   139  		name := f[2]
   140  		if addr, found := names[name]; found {
   141  			if want, have := addr, "0x"+f[0]; have != want {
   142  				t.Errorf("want %s address for %s symbol, but have %s", want, name, have)
   143  			}
   144  			delete(names, name)
   145  		}
   146  		if _, found := dups[name]; found {
   147  			t.Errorf("duplicate name of %q is found", name)
   148  		}
   149  	}
   150  	err = scanner.Err()
   151  	if err != nil {
   152  		t.Fatalf("error reading nm output: %v", err)
   153  	}
   154  	if len(names) > 0 {
   155  		t.Errorf("executable is missing %v symbols", names)
   156  	}
   157  }
   158  
   159  func TestGoFile(t *testing.T) {
   160  	testGoFile(t, false, false)
   161  }
   162  
   163  const testprog = `
   164  package main
   165  
   166  import "fmt"
   167  {{if .}}import "C"
   168  {{end}}
   169  
   170  func main() {
   171  	testfunc()
   172  }
   173  
   174  var testdata uint32
   175  
   176  func testfunc() {
   177  	fmt.Printf("main=%p\n", main)
   178  	fmt.Printf("testfunc=%p\n", testfunc)
   179  	fmt.Printf("testdata=%p\n", &testdata)
   180  }
   181  `