blob: 6e2b78a5788e9a4364e9cfaadf370e668b8e60f6 [file] [log] [blame]
// Copyright 2009 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 tar
import (
"bytes";
"fmt";
"io";
"testing";
"testing/iotest";
)
type writerTestEntry struct {
header *Header;
contents string;
}
type writerTest struct {
file string; // filename of expected output
entries []*writerTestEntry;
}
var writerTests = []*writerTest{
&writerTest{
file: "testdata/writer.tar",
entries: []*writerTestEntry{
&writerTestEntry{
header: &Header{
Name: "small.txt",
Mode: 0640,
Uid: 73025,
Gid: 5000,
Size: 5,
Mtime: 1246508266,
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
},
contents: "Kilts",
},
&writerTestEntry{
header: &Header{
Name: "small2.txt",
Mode: 0640,
Uid: 73025,
Gid: 5000,
Size: 11,
Mtime: 1245217492,
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
},
contents: "Google.com\n",
},
},
},
// The truncated test file was produced using these commands:
// dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
// tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
&writerTest{
file: "testdata/writer-big.tar",
entries: []*writerTestEntry{
&writerTestEntry{
header: &Header{
Name: "tmp/16gig.txt",
Mode: 0640,
Uid: 73025,
Gid: 5000,
Size: 16 << 30,
Mtime: 1254699560,
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
},
// no contents
},
},
},
}
// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
func bytestr(offset int, b []byte) string {
const rowLen = 32;
s := fmt.Sprintf("%04x ", offset);
for _, ch := range b {
switch {
case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z':
s += fmt.Sprintf(" %c", ch)
default:
s += fmt.Sprintf(" %02x", ch)
}
}
return s;
}
// Render a pseudo-diff between two blocks of bytes.
func bytediff(a []byte, b []byte) string {
const rowLen = 32;
s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b));
for offset := 0; len(a)+len(b) > 0; offset += rowLen {
na, nb := rowLen, rowLen;
if na > len(a) {
na = len(a)
}
if nb > len(b) {
nb = len(b)
}
sa := bytestr(offset, a[0:na]);
sb := bytestr(offset, b[0:nb]);
if sa != sb {
s += fmt.Sprintf("-%v\n+%v\n", sa, sb)
}
a = a[na:len(a)];
b = b[nb:len(b)];
}
return s;
}
func TestWriter(t *testing.T) {
testLoop:
for i, test := range writerTests {
expected, err := io.ReadFile(test.file);
if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err);
continue;
}
buf := new(bytes.Buffer);
tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)); // only catch the first 4 KB
for j, entry := range test.entries {
if err := tw.WriteHeader(entry.header); err != nil {
t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err);
continue testLoop;
}
if _, err := io.WriteString(tw, entry.contents); err != nil {
t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err);
continue testLoop;
}
}
if err := tw.Close(); err != nil {
t.Errorf("test %d: Failed closing archive: %v", err);
continue testLoop;
}
actual := buf.Bytes();
if !bytes.Equal(expected, actual) {
t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
i, bytediff(expected, actual))
}
}
}