...
Run Format

Source file src/cmd/pack/pack_test.go

Documentation: cmd/pack

  // 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 (
  	"bufio"
  	"bytes"
  	"fmt"
  	"internal/testenv"
  	"io"
  	"io/ioutil"
  	"os"
  	"os/exec"
  	"path/filepath"
  	"testing"
  	"time"
  	"unicode/utf8"
  )
  
  func TestExactly16Bytes(t *testing.T) {
  	var tests = []string{
  		"",
  		"a",
  		"日本語",
  		"1234567890123456",
  		"12345678901234567890",
  		"1234567890123本語4567890",
  		"12345678901234日本語567890",
  		"123456789012345日本語67890",
  		"1234567890123456日本語7890",
  		"1234567890123456日本語7日本語890",
  	}
  	for _, str := range tests {
  		got := exactly16Bytes(str)
  		if len(got) != 16 {
  			t.Errorf("exactly16Bytes(%q) is %q, length %d", str, got, len(got))
  		}
  		// Make sure it is full runes.
  		for _, c := range got {
  			if c == utf8.RuneError {
  				t.Errorf("exactly16Bytes(%q) is %q, has partial rune", str, got)
  			}
  		}
  	}
  }
  
  // tmpDir creates a temporary directory and returns its name.
  func tmpDir(t *testing.T) string {
  	name, err := ioutil.TempDir("", "pack")
  	if err != nil {
  		t.Fatal(err)
  	}
  	return name
  }
  
  // testCreate creates an archive in the specified directory.
  func testCreate(t *testing.T, dir string) {
  	name := filepath.Join(dir, "pack.a")
  	ar := archive(name, os.O_RDWR, nil)
  	// Add an entry by hand.
  	ar.addFile(helloFile.Reset())
  	ar.fd.Close()
  	// Now check it.
  	ar = archive(name, os.O_RDONLY, []string{helloFile.name})
  	var buf bytes.Buffer
  	stdout = &buf
  	verbose = true
  	defer func() {
  		stdout = os.Stdout
  		verbose = false
  	}()
  	ar.scan(ar.printContents)
  	ar.fd.Close()
  	result := buf.String()
  	// Expect verbose output plus file contents.
  	expect := fmt.Sprintf("%s\n%s", helloFile.name, helloFile.contents)
  	if result != expect {
  		t.Fatalf("expected %q got %q", expect, result)
  	}
  }
  
  // Test that we can create an archive, write to it, and get the same contents back.
  // Tests the rv and then the pv command on a new archive.
  func TestCreate(t *testing.T) {
  	dir := tmpDir(t)
  	defer os.RemoveAll(dir)
  	testCreate(t, dir)
  }
  
  // Test that we can create an archive twice with the same name (Issue 8369).
  func TestCreateTwice(t *testing.T) {
  	dir := tmpDir(t)
  	defer os.RemoveAll(dir)
  	testCreate(t, dir)
  	testCreate(t, dir)
  }
  
  // Test that we can create an archive, put some files in it, and get back a correct listing.
  // Tests the tv command.
  func TestTableOfContents(t *testing.T) {
  	dir := tmpDir(t)
  	defer os.RemoveAll(dir)
  	name := filepath.Join(dir, "pack.a")
  	ar := archive(name, os.O_RDWR, nil)
  
  	// Add some entries by hand.
  	ar.addFile(helloFile.Reset())
  	ar.addFile(goodbyeFile.Reset())
  	ar.fd.Close()
  
  	// Now print it.
  	ar = archive(name, os.O_RDONLY, nil)
  	var buf bytes.Buffer
  	stdout = &buf
  	verbose = true
  	defer func() {
  		stdout = os.Stdout
  		verbose = false
  	}()
  	ar.scan(ar.tableOfContents)
  	ar.fd.Close()
  	result := buf.String()
  	// Expect verbose listing.
  	expect := fmt.Sprintf("%s\n%s\n", helloFile.Entry(), goodbyeFile.Entry())
  	if result != expect {
  		t.Fatalf("expected %q got %q", expect, result)
  	}
  
  	// Do it again without verbose.
  	verbose = false
  	buf.Reset()
  	ar = archive(name, os.O_RDONLY, nil)
  	ar.scan(ar.tableOfContents)
  	ar.fd.Close()
  	result = buf.String()
  	// Expect non-verbose listing.
  	expect = fmt.Sprintf("%s\n%s\n", helloFile.name, goodbyeFile.name)
  	if result != expect {
  		t.Fatalf("expected %q got %q", expect, result)
  	}
  
  	// Do it again with file list arguments.
  	verbose = false
  	buf.Reset()
  	ar = archive(name, os.O_RDONLY, []string{helloFile.name})
  	ar.scan(ar.tableOfContents)
  	ar.fd.Close()
  	result = buf.String()
  	// Expect only helloFile.
  	expect = fmt.Sprintf("%s\n", helloFile.name)
  	if result != expect {
  		t.Fatalf("expected %q got %q", expect, result)
  	}
  }
  
  // Test that we can create an archive, put some files in it, and get back a file.
  // Tests the x command.
  func TestExtract(t *testing.T) {
  	dir := tmpDir(t)
  	defer os.RemoveAll(dir)
  	name := filepath.Join(dir, "pack.a")
  	ar := archive(name, os.O_RDWR, nil)
  	// Add some entries by hand.
  	ar.addFile(helloFile.Reset())
  	ar.addFile(goodbyeFile.Reset())
  	ar.fd.Close()
  	// Now extract one file. We chdir to the directory of the archive for simplicity.
  	pwd, err := os.Getwd()
  	if err != nil {
  		t.Fatal("os.Getwd: ", err)
  	}
  	err = os.Chdir(dir)
  	if err != nil {
  		t.Fatal("os.Chdir: ", err)
  	}
  	defer func() {
  		err := os.Chdir(pwd)
  		if err != nil {
  			t.Fatal("os.Chdir: ", err)
  		}
  	}()
  	ar = archive(name, os.O_RDONLY, []string{goodbyeFile.name})
  	ar.scan(ar.extractContents)
  	ar.fd.Close()
  	data, err := ioutil.ReadFile(goodbyeFile.name)
  	if err != nil {
  		t.Fatal(err)
  	}
  	// Expect contents of file.
  	result := string(data)
  	expect := goodbyeFile.contents
  	if result != expect {
  		t.Fatalf("expected %q got %q", expect, result)
  	}
  }
  
  // Test that pack-created archives can be understood by the tools.
  func TestHello(t *testing.T) {
  	testenv.MustHaveGoBuild(t)
  
  	dir := tmpDir(t)
  	defer os.RemoveAll(dir)
  	hello := filepath.Join(dir, "hello.go")
  	prog := `
  		package main
  		func main() {
  			println("hello world")
  		}
  	`
  	err := ioutil.WriteFile(hello, []byte(prog), 0666)
  	if err != nil {
  		t.Fatal(err)
  	}
  
  	run := func(args ...string) string {
  		return doRun(t, dir, args...)
  	}
  
  	goBin := testenv.GoToolPath(t)
  	run(goBin, "build", "cmd/pack") // writes pack binary to dir
  	run(goBin, "tool", "compile", "hello.go")
  	run("./pack", "grc", "hello.a", "hello.o")
  	run(goBin, "tool", "link", "-o", "a.out", "hello.a")
  	out := run("./a.out")
  	if out != "hello world\n" {
  		t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
  	}
  }
  
  // Test that pack works with very long lines in PKGDEF.
  func TestLargeDefs(t *testing.T) {
  	testenv.MustHaveGoBuild(t)
  
  	dir := tmpDir(t)
  	defer os.RemoveAll(dir)
  	large := filepath.Join(dir, "large.go")
  	f, err := os.Create(large)
  	if err != nil {
  		t.Fatal(err)
  	}
  	b := bufio.NewWriter(f)
  
  	printf := func(format string, args ...interface{}) {
  		_, err := fmt.Fprintf(b, format, args...)
  		if err != nil {
  			t.Fatalf("Writing to %s: %v", large, err)
  		}
  	}
  
  	printf("package large\n\ntype T struct {\n")
  	for i := 0; i < 1000; i++ {
  		printf("f%d int `tag:\"", i)
  		for j := 0; j < 100; j++ {
  			printf("t%d=%d,", j, j)
  		}
  		printf("\"`\n")
  	}
  	printf("}\n")
  	if err = b.Flush(); err != nil {
  		t.Fatal(err)
  	}
  	if err = f.Close(); err != nil {
  		t.Fatal(err)
  	}
  
  	main := filepath.Join(dir, "main.go")
  	prog := `
  		package main
  		import "large"
  		var V large.T
  		func main() {
  			println("ok")
  		}
  	`
  	err = ioutil.WriteFile(main, []byte(prog), 0666)
  	if err != nil {
  		t.Fatal(err)
  	}
  
  	run := func(args ...string) string {
  		return doRun(t, dir, args...)
  	}
  
  	goBin := testenv.GoToolPath(t)
  	run(goBin, "build", "cmd/pack") // writes pack binary to dir
  	run(goBin, "tool", "compile", "large.go")
  	run("./pack", "grc", "large.a", "large.o")
  	run(goBin, "tool", "compile", "-I", ".", "main.go")
  	run(goBin, "tool", "link", "-L", ".", "-o", "a.out", "main.o")
  	out := run("./a.out")
  	if out != "ok\n" {
  		t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
  	}
  }
  
  // doRun runs a program in a directory and returns the output.
  func doRun(t *testing.T, dir string, args ...string) string {
  	cmd := exec.Command(args[0], args[1:]...)
  	cmd.Dir = dir
  	out, err := cmd.CombinedOutput()
  	if err != nil {
  		t.Fatalf("%v: %v\n%s", args, err, string(out))
  	}
  	return string(out)
  }
  
  // Fake implementation of files.
  
  var helloFile = &FakeFile{
  	name:     "hello",
  	contents: "hello world", // 11 bytes, an odd number.
  	mode:     0644,
  }
  
  var goodbyeFile = &FakeFile{
  	name:     "goodbye",
  	contents: "Sayonara, Jim", // 13 bytes, another odd number.
  	mode:     0644,
  }
  
  // FakeFile implements FileLike and also os.FileInfo.
  type FakeFile struct {
  	name     string
  	contents string
  	mode     os.FileMode
  	offset   int
  }
  
  // Reset prepares a FakeFile for reuse.
  func (f *FakeFile) Reset() *FakeFile {
  	f.offset = 0
  	return f
  }
  
  // FileLike methods.
  
  func (f *FakeFile) Name() string {
  	// A bit of a cheat: we only have a basename, so that's also ok for FileInfo.
  	return f.name
  }
  
  func (f *FakeFile) Stat() (os.FileInfo, error) {
  	return f, nil
  }
  
  func (f *FakeFile) Read(p []byte) (int, error) {
  	if f.offset >= len(f.contents) {
  		return 0, io.EOF
  	}
  	n := copy(p, f.contents[f.offset:])
  	f.offset += n
  	return n, nil
  }
  
  func (f *FakeFile) Close() error {
  	return nil
  }
  
  // os.FileInfo methods.
  
  func (f *FakeFile) Size() int64 {
  	return int64(len(f.contents))
  }
  
  func (f *FakeFile) Mode() os.FileMode {
  	return f.mode
  }
  
  func (f *FakeFile) ModTime() time.Time {
  	return time.Time{}
  }
  
  func (f *FakeFile) IsDir() bool {
  	return false
  }
  
  func (f *FakeFile) Sys() interface{} {
  	return nil
  }
  
  // Special helpers.
  
  func (f *FakeFile) Entry() *Entry {
  	return &Entry{
  		name:  f.name,
  		mtime: 0, // Defined to be zero.
  		uid:   0, // Ditto.
  		gid:   0, // Ditto.
  		mode:  f.mode,
  		size:  int64(len(f.contents)),
  	}
  }
  

View as plain text