1 // Copyright 2009 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.
19 type writerTestEntry
struct {
24 type writerTest
struct {
25 file
string // filename of expected output
26 entries
[]*writerTestEntry
29 var writerTests
= []*writerTest
{
30 // The writer test file was produced with this command:
32 // ln -s small.txt link.txt
33 // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
35 file
: "testdata/writer.tar",
36 entries
: []*writerTestEntry
{
44 ModTime
: time
.Unix(1246508266, 0),
58 ModTime
: time
.Unix(1245217492, 0),
63 contents
: "Google.com\n",
72 ModTime
: time
.Unix(1314603082, 0),
74 Linkname
: "small.txt",
82 // The truncated test file was produced using these commands:
83 // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
84 // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
86 file
: "testdata/writer-big.tar",
87 entries
: []*writerTestEntry
{
90 Name
: "tmp/16gig.txt",
95 ModTime
: time
.Unix(1254699560, 0),
101 contents
: strings
.Repeat("\x00", 4<<10),
105 // This file was produced using gnu tar 1.17
106 // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
108 file
: "testdata/ustar.tar",
109 entries
: []*writerTestEntry
{
112 Name
: strings
.Repeat("longname/", 15) + "file.txt",
117 ModTime
: time
.Unix(1360135598, 0),
128 // Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
129 func bytestr(offset
int, b
[]byte) string {
131 s
:= fmt
.Sprintf("%04x ", offset
)
132 for _
, ch
:= range b
{
134 case '0' <= ch
&& ch
<= '9', 'A' <= ch
&& ch
<= 'Z', 'a' <= ch
&& ch
<= 'z':
135 s
+= fmt
.Sprintf(" %c", ch
)
137 s
+= fmt
.Sprintf(" %02x", ch
)
143 // Render a pseudo-diff between two blocks of bytes.
144 func bytediff(a
[]byte, b
[]byte) string {
146 s
:= fmt
.Sprintf("(%d bytes vs. %d bytes)\n", len(a
), len(b
))
147 for offset
:= 0; len(a
)+len(b
) > 0; offset
+= rowLen
{
148 na
, nb
:= rowLen
, rowLen
155 sa
:= bytestr(offset
, a
[0:na
])
156 sb
:= bytestr(offset
, b
[0:nb
])
158 s
+= fmt
.Sprintf("-%v\n+%v\n", sa
, sb
)
166 func TestWriter(t
*testing
.T
) {
168 for i
, test
:= range writerTests
{
169 expected
, err
:= ioutil
.ReadFile(test
.file
)
171 t
.Errorf("test %d: Unexpected error: %v", i
, err
)
175 buf
:= new(bytes
.Buffer
)
176 tw
:= NewWriter(iotest
.TruncateWriter(buf
, 4<<10)) // only catch the first 4 KB
178 for j
, entry
:= range test
.entries
{
179 big
= big || entry
.header
.Size
> 1<<10
180 if err
:= tw
.WriteHeader(entry
.header
); err
!= nil {
181 t
.Errorf("test %d, entry %d: Failed writing header: %v", i
, j
, err
)
184 if _
, err
:= io
.WriteString(tw
, entry
.contents
); err
!= nil {
185 t
.Errorf("test %d, entry %d: Failed writing contents: %v", i
, j
, err
)
189 // Only interested in Close failures for the small tests.
190 if err
:= tw
.Close(); err
!= nil && !big
{
191 t
.Errorf("test %d: Failed closing archive: %v", i
, err
)
195 actual
:= buf
.Bytes()
196 if !bytes
.Equal(expected
, actual
) {
197 t
.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
198 i
, bytediff(expected
, actual
))
200 if testing
.Short() { // The second test is expensive.
206 func TestPax(t
*testing
.T
) {
207 // Create an archive with a large name
208 fileinfo
, err
:= os
.Stat("testdata/small.txt")
212 hdr
, err
:= FileInfoHeader(fileinfo
, "")
214 t
.Fatalf("os.Stat: %v", err
)
216 // Force a PAX long name to be written
217 longName
:= strings
.Repeat("ab", 100)
218 contents
:= strings
.Repeat(" ", int(hdr
.Size
))
221 writer
:= NewWriter(&buf
)
222 if err
:= writer
.WriteHeader(hdr
); err
!= nil {
225 if _
, err
= writer
.Write([]byte(contents
)); err
!= nil {
228 if err
:= writer
.Close(); err
!= nil {
231 // Simple test to make sure PAX extensions are in effect
232 if !bytes
.Contains(buf
.Bytes(), []byte("PaxHeaders.")) {
233 t
.Fatal("Expected at least one PAX header to be written.")
235 // Test that we can get a long name back out of the archive.
236 reader
:= NewReader(&buf
)
237 hdr
, err
= reader
.Next()
241 if hdr
.Name
!= longName
{
242 t
.Fatal("Couldn't recover long file name")
246 func TestPAXHeader(t
*testing
.T
) {
247 medName
:= strings
.Repeat("CD", 50)
248 longName
:= strings
.Repeat("AB", 100)
249 paxTests
:= [][2]string{
250 {"name=/etc/hosts", "19 name=/etc/hosts\n"},
251 {"a=b", "6 a=b\n"}, // Single digit length
252 {"a=names", "11 a=names\n"}, // Test case involving carries
253 {"name=" + longName
, fmt
.Sprintf("210 name=%s\n", longName
)},
254 {"name=" + medName
, fmt
.Sprintf("110 name=%s\n", medName
)}}
256 for _
, test
:= range paxTests
{
257 key
, expected
:= test
[0], test
[1]
258 if result
:= paxHeader(key
); result
!= expected
{
259 t
.Fatalf("paxHeader: got %s, expected %s", result
, expected
)