...
Run Format

Source file src/cmd/pack/pack_test.go

Documentation: cmd/pack

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

View as plain text