mirror of https://github.com/golang/go.git
253 lines
5.5 KiB
Go
253 lines
5.5 KiB
Go
// 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 (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"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
|
|
}
|
|
|
|
// 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)
|
|
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, 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)
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
// 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)),
|
|
}
|
|
}
|