github.com/hongwozai/go-src-1.4.3@v0.0.0-20191127132709-dc3fce3dbccb/src/cmd/pack/pack_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  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"regexp"
    17  	"runtime"
    18  	"testing"
    19  	"time"
    20  	"unicode/utf8"
    21  )
    22  
    23  func TestExactly16Bytes(t *testing.T) {
    24  	var tests = []string{
    25  		"",
    26  		"a",
    27  		"日本語",
    28  		"1234567890123456",
    29  		"12345678901234567890",
    30  		"1234567890123本語4567890",
    31  		"12345678901234日本語567890",
    32  		"123456789012345日本語67890",
    33  		"1234567890123456日本語7890",
    34  		"1234567890123456日本語7日本語890",
    35  	}
    36  	for _, str := range tests {
    37  		got := exactly16Bytes(str)
    38  		if len(got) != 16 {
    39  			t.Errorf("exactly16Bytes(%q) is %q, length %d", str, got, len(got))
    40  		}
    41  		// Make sure it is full runes.
    42  		for _, c := range got {
    43  			if c == utf8.RuneError {
    44  				t.Errorf("exactly16Bytes(%q) is %q, has partial rune", str, got)
    45  			}
    46  		}
    47  	}
    48  }
    49  
    50  // tmpDir creates a temporary directory and returns its name.
    51  func tmpDir(t *testing.T) string {
    52  	name, err := ioutil.TempDir("", "pack")
    53  	if err != nil {
    54  		t.Fatal(err)
    55  	}
    56  	return name
    57  }
    58  
    59  // testCreate creates an archive in the specified directory.
    60  func testCreate(t *testing.T, dir string) {
    61  	name := filepath.Join(dir, "pack.a")
    62  	ar := archive(name, os.O_RDWR, nil)
    63  	// Add an entry by hand.
    64  	ar.addFile(helloFile.Reset())
    65  	ar.fd.Close()
    66  	// Now check it.
    67  	ar = archive(name, os.O_RDONLY, []string{helloFile.name})
    68  	var buf bytes.Buffer
    69  	stdout = &buf
    70  	verbose = true
    71  	defer func() {
    72  		stdout = os.Stdout
    73  		verbose = false
    74  	}()
    75  	ar.scan(ar.printContents)
    76  	ar.fd.Close()
    77  	result := buf.String()
    78  	// Expect verbose output plus file contents.
    79  	expect := fmt.Sprintf("%s\n%s", helloFile.name, helloFile.contents)
    80  	if result != expect {
    81  		t.Fatalf("expected %q got %q", expect, result)
    82  	}
    83  }
    84  
    85  // Test that we can create an archive, write to it, and get the same contents back.
    86  // Tests the rv and then the pv command on a new archive.
    87  func TestCreate(t *testing.T) {
    88  	dir := tmpDir(t)
    89  	defer os.RemoveAll(dir)
    90  	testCreate(t, dir)
    91  }
    92  
    93  // Test that we can create an archive twice with the same name (Issue 8369).
    94  func TestCreateTwice(t *testing.T) {
    95  	dir := tmpDir(t)
    96  	defer os.RemoveAll(dir)
    97  	testCreate(t, dir)
    98  	testCreate(t, dir)
    99  }
   100  
   101  // Test that we can create an archive, put some files in it, and get back a correct listing.
   102  // Tests the tv command.
   103  func TestTableOfContents(t *testing.T) {
   104  	dir := tmpDir(t)
   105  	defer os.RemoveAll(dir)
   106  	name := filepath.Join(dir, "pack.a")
   107  	ar := archive(name, os.O_RDWR, nil)
   108  
   109  	// Add some entries by hand.
   110  	ar.addFile(helloFile.Reset())
   111  	ar.addFile(goodbyeFile.Reset())
   112  	ar.fd.Close()
   113  
   114  	// Now print it.
   115  	ar = archive(name, os.O_RDONLY, nil)
   116  	var buf bytes.Buffer
   117  	stdout = &buf
   118  	verbose = true
   119  	defer func() {
   120  		stdout = os.Stdout
   121  		verbose = false
   122  	}()
   123  	ar.scan(ar.tableOfContents)
   124  	ar.fd.Close()
   125  	result := buf.String()
   126  	// Expect verbose listing.
   127  	expect := fmt.Sprintf("%s\n%s\n", helloFile.Entry(), goodbyeFile.Entry())
   128  	if result != expect {
   129  		t.Fatalf("expected %q got %q", expect, result)
   130  	}
   131  
   132  	// Do it again without verbose.
   133  	verbose = false
   134  	buf.Reset()
   135  	ar = archive(name, os.O_RDONLY, nil)
   136  	ar.scan(ar.tableOfContents)
   137  	ar.fd.Close()
   138  	result = buf.String()
   139  	// Expect non-verbose listing.
   140  	expect = fmt.Sprintf("%s\n%s\n", helloFile.name, goodbyeFile.name)
   141  	if result != expect {
   142  		t.Fatalf("expected %q got %q", expect, result)
   143  	}
   144  
   145  	// Do it again with file list arguments.
   146  	verbose = false
   147  	buf.Reset()
   148  	ar = archive(name, os.O_RDONLY, []string{helloFile.name})
   149  	ar.scan(ar.tableOfContents)
   150  	ar.fd.Close()
   151  	result = buf.String()
   152  	// Expect only helloFile.
   153  	expect = fmt.Sprintf("%s\n", helloFile.name)
   154  	if result != expect {
   155  		t.Fatalf("expected %q got %q", expect, result)
   156  	}
   157  }
   158  
   159  // Test that we can create an archive, put some files in it, and get back a file.
   160  // Tests the x command.
   161  func TestExtract(t *testing.T) {
   162  	dir := tmpDir(t)
   163  	defer os.RemoveAll(dir)
   164  	name := filepath.Join(dir, "pack.a")
   165  	ar := archive(name, os.O_RDWR, nil)
   166  	// Add some entries by hand.
   167  	ar.addFile(helloFile.Reset())
   168  	ar.addFile(goodbyeFile.Reset())
   169  	ar.fd.Close()
   170  	// Now extract one file. We chdir to the directory of the archive for simplicity.
   171  	pwd, err := os.Getwd()
   172  	if err != nil {
   173  		t.Fatal("os.Getwd: ", err)
   174  	}
   175  	err = os.Chdir(dir)
   176  	if err != nil {
   177  		t.Fatal("os.Chdir: ", err)
   178  	}
   179  	defer func() {
   180  		err := os.Chdir(pwd)
   181  		if err != nil {
   182  			t.Fatal("os.Chdir: ", err)
   183  		}
   184  	}()
   185  	ar = archive(name, os.O_RDONLY, []string{goodbyeFile.name})
   186  	ar.scan(ar.extractContents)
   187  	ar.fd.Close()
   188  	data, err := ioutil.ReadFile(goodbyeFile.name)
   189  	if err != nil {
   190  		t.Fatal(err)
   191  	}
   192  	// Expect contents of file.
   193  	result := string(data)
   194  	expect := goodbyeFile.contents
   195  	if result != expect {
   196  		t.Fatalf("expected %q got %q", expect, result)
   197  	}
   198  }
   199  
   200  // Test that pack-created archives can be understood by the tools.
   201  func TestHello(t *testing.T) {
   202  	switch runtime.GOOS {
   203  	case "android", "nacl":
   204  		t.Skipf("skipping on %s", runtime.GOOS)
   205  	}
   206  
   207  	dir := tmpDir(t)
   208  	defer os.RemoveAll(dir)
   209  	hello := filepath.Join(dir, "hello.go")
   210  	prog := `
   211  		package main
   212  		func main() {
   213  			println("hello world")
   214  		}
   215  	`
   216  	err := ioutil.WriteFile(hello, []byte(prog), 0666)
   217  	if err != nil {
   218  		t.Fatal(err)
   219  	}
   220  
   221  	char := findChar(t, dir)
   222  
   223  	run := func(args ...string) string {
   224  		return doRun(t, dir, args...)
   225  	}
   226  
   227  	run("go", "build", "cmd/pack") // writes pack binary to dir
   228  	run("go", "tool", char+"g", "hello.go")
   229  	run("./pack", "grc", "hello.a", "hello."+char)
   230  	run("go", "tool", char+"l", "-o", "a.out", "hello.a")
   231  	out := run("./a.out")
   232  	if out != "hello world\n" {
   233  		t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
   234  	}
   235  }
   236  
   237  // Test that pack works with very long lines in PKGDEF.
   238  func TestLargeDefs(t *testing.T) {
   239  	switch runtime.GOOS {
   240  	case "android", "nacl":
   241  		t.Skipf("skipping on %s", runtime.GOOS)
   242  	}
   243  
   244  	dir := tmpDir(t)
   245  	defer os.RemoveAll(dir)
   246  	large := filepath.Join(dir, "large.go")
   247  	f, err := os.Create(large)
   248  	if err != nil {
   249  		t.Fatal(err)
   250  	}
   251  	b := bufio.NewWriter(f)
   252  
   253  	printf := func(format string, args ...interface{}) {
   254  		_, err := fmt.Fprintf(b, format, args...)
   255  		if err != nil {
   256  			t.Fatalf("Writing to %s: %v", large, err)
   257  		}
   258  	}
   259  
   260  	printf("package large\n\ntype T struct {\n")
   261  	for i := 0; i < 10000; i++ {
   262  		printf("f%d int `tag:\"", i)
   263  		for j := 0; j < 100; j++ {
   264  			printf("t%d=%d,", j, j)
   265  		}
   266  		printf("\"`\n")
   267  	}
   268  	printf("}\n")
   269  	if err = b.Flush(); err != nil {
   270  		t.Fatal(err)
   271  	}
   272  	if err = f.Close(); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  
   276  	main := filepath.Join(dir, "main.go")
   277  	prog := `
   278  		package main
   279  		import "large"
   280  		var V large.T
   281  		func main() {
   282  			println("ok")
   283  		}
   284  	`
   285  	err = ioutil.WriteFile(main, []byte(prog), 0666)
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  
   290  	char := findChar(t, dir)
   291  
   292  	run := func(args ...string) string {
   293  		return doRun(t, dir, args...)
   294  	}
   295  
   296  	run("go", "build", "cmd/pack") // writes pack binary to dir
   297  	run("go", "tool", char+"g", "large.go")
   298  	run("./pack", "grc", "large.a", "large."+char)
   299  	run("go", "tool", char+"g", "-I", ".", "main.go")
   300  	run("go", "tool", char+"l", "-L", ".", "-o", "a.out", "main."+char)
   301  	out := run("./a.out")
   302  	if out != "ok\n" {
   303  		t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
   304  	}
   305  }
   306  
   307  // doRun runs a program in a directory and returns the output.
   308  func doRun(t *testing.T, dir string, args ...string) string {
   309  	cmd := exec.Command(args[0], args[1:]...)
   310  	cmd.Dir = dir
   311  	out, err := cmd.CombinedOutput()
   312  	if err != nil {
   313  		t.Fatalf("%v: %v\n%s", args, err, string(out))
   314  	}
   315  	return string(out)
   316  }
   317  
   318  // findChar returns the architecture character for the go command.
   319  func findChar(t *testing.T, dir string) string {
   320  	out := doRun(t, dir, "go", "env")
   321  	re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`)
   322  	if err != nil {
   323  		t.Fatal(err)
   324  	}
   325  	fields := re.FindStringSubmatch(out)
   326  	if fields == nil {
   327  		t.Fatal("cannot find GOCHAR in 'go env' output:\n", out)
   328  	}
   329  	return fields[1]
   330  }
   331  
   332  // Fake implementation of files.
   333  
   334  var helloFile = &FakeFile{
   335  	name:     "hello",
   336  	contents: "hello world", // 11 bytes, an odd number.
   337  	mode:     0644,
   338  }
   339  
   340  var goodbyeFile = &FakeFile{
   341  	name:     "goodbye",
   342  	contents: "Sayonara, Jim", // 13 bytes, another odd number.
   343  	mode:     0644,
   344  }
   345  
   346  // FakeFile implements FileLike and also os.FileInfo.
   347  type FakeFile struct {
   348  	name     string
   349  	contents string
   350  	mode     os.FileMode
   351  	offset   int
   352  }
   353  
   354  // Reset prepares a FakeFile for reuse.
   355  func (f *FakeFile) Reset() *FakeFile {
   356  	f.offset = 0
   357  	return f
   358  }
   359  
   360  // FileLike methods.
   361  
   362  func (f *FakeFile) Name() string {
   363  	// A bit of a cheat: we only have a basename, so that's also ok for FileInfo.
   364  	return f.name
   365  }
   366  
   367  func (f *FakeFile) Stat() (os.FileInfo, error) {
   368  	return f, nil
   369  }
   370  
   371  func (f *FakeFile) Read(p []byte) (int, error) {
   372  	if f.offset >= len(f.contents) {
   373  		return 0, io.EOF
   374  	}
   375  	n := copy(p, f.contents[f.offset:])
   376  	f.offset += n
   377  	return n, nil
   378  }
   379  
   380  func (f *FakeFile) Close() error {
   381  	return nil
   382  }
   383  
   384  // os.FileInfo methods.
   385  
   386  func (f *FakeFile) Size() int64 {
   387  	return int64(len(f.contents))
   388  }
   389  
   390  func (f *FakeFile) Mode() os.FileMode {
   391  	return f.mode
   392  }
   393  
   394  func (f *FakeFile) ModTime() time.Time {
   395  	return time.Time{}
   396  }
   397  
   398  func (f *FakeFile) IsDir() bool {
   399  	return false
   400  }
   401  
   402  func (f *FakeFile) Sys() interface{} {
   403  	return nil
   404  }
   405  
   406  // Special helpers.
   407  
   408  func (f *FakeFile) Entry() *Entry {
   409  	return &Entry{
   410  		name:  f.name,
   411  		mtime: 0, // Defined to be zero.
   412  		uid:   0, // Ditto.
   413  		gid:   0, // Ditto.
   414  		mode:  f.mode,
   415  		size:  int64(len(f.contents)),
   416  	}
   417  }