libgo: Update to Go 1.3 release.
[official-gcc.git] / libgo / go / archive / tar / writer_test.go
blob512fab1a6f1c18496f7ca834dff08347c814f0cf
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.
5 package tar
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "io/ioutil"
12 "os"
13 "reflect"
14 "strings"
15 "testing"
16 "testing/iotest"
17 "time"
20 type writerTestEntry struct {
21 header *Header
22 contents string
25 type writerTest struct {
26 file string // filename of expected output
27 entries []*writerTestEntry
30 var writerTests = []*writerTest{
31 // The writer test file was produced with this command:
32 // tar (GNU tar) 1.26
33 // ln -s small.txt link.txt
34 // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
36 file: "testdata/writer.tar",
37 entries: []*writerTestEntry{
39 header: &Header{
40 Name: "small.txt",
41 Mode: 0640,
42 Uid: 73025,
43 Gid: 5000,
44 Size: 5,
45 ModTime: time.Unix(1246508266, 0),
46 Typeflag: '0',
47 Uname: "dsymonds",
48 Gname: "eng",
50 contents: "Kilts",
53 header: &Header{
54 Name: "small2.txt",
55 Mode: 0640,
56 Uid: 73025,
57 Gid: 5000,
58 Size: 11,
59 ModTime: time.Unix(1245217492, 0),
60 Typeflag: '0',
61 Uname: "dsymonds",
62 Gname: "eng",
64 contents: "Google.com\n",
67 header: &Header{
68 Name: "link.txt",
69 Mode: 0777,
70 Uid: 1000,
71 Gid: 1000,
72 Size: 0,
73 ModTime: time.Unix(1314603082, 0),
74 Typeflag: '2',
75 Linkname: "small.txt",
76 Uname: "strings",
77 Gname: "strings",
79 // no contents
83 // The truncated test file was produced using these commands:
84 // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
85 // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
87 file: "testdata/writer-big.tar",
88 entries: []*writerTestEntry{
90 header: &Header{
91 Name: "tmp/16gig.txt",
92 Mode: 0640,
93 Uid: 73025,
94 Gid: 5000,
95 Size: 16 << 30,
96 ModTime: time.Unix(1254699560, 0),
97 Typeflag: '0',
98 Uname: "dsymonds",
99 Gname: "eng",
101 // fake contents
102 contents: strings.Repeat("\x00", 4<<10),
106 // The truncated test file was produced using these commands:
107 // dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
108 // tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
110 file: "testdata/writer-big-long.tar",
111 entries: []*writerTestEntry{
113 header: &Header{
114 Name: strings.Repeat("longname/", 15) + "16gig.txt",
115 Mode: 0644,
116 Uid: 1000,
117 Gid: 1000,
118 Size: 16 << 30,
119 ModTime: time.Unix(1399583047, 0),
120 Typeflag: '0',
121 Uname: "guillaume",
122 Gname: "guillaume",
124 // fake contents
125 contents: strings.Repeat("\x00", 4<<10),
129 // This file was produced using gnu tar 1.17
130 // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
132 file: "testdata/ustar.tar",
133 entries: []*writerTestEntry{
135 header: &Header{
136 Name: strings.Repeat("longname/", 15) + "file.txt",
137 Mode: 0644,
138 Uid: 0765,
139 Gid: 024,
140 Size: 06,
141 ModTime: time.Unix(1360135598, 0),
142 Typeflag: '0',
143 Uname: "shane",
144 Gname: "staff",
146 contents: "hello\n",
152 // Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
153 func bytestr(offset int, b []byte) string {
154 const rowLen = 32
155 s := fmt.Sprintf("%04x ", offset)
156 for _, ch := range b {
157 switch {
158 case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z':
159 s += fmt.Sprintf(" %c", ch)
160 default:
161 s += fmt.Sprintf(" %02x", ch)
164 return s
167 // Render a pseudo-diff between two blocks of bytes.
168 func bytediff(a []byte, b []byte) string {
169 const rowLen = 32
170 s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b))
171 for offset := 0; len(a)+len(b) > 0; offset += rowLen {
172 na, nb := rowLen, rowLen
173 if na > len(a) {
174 na = len(a)
176 if nb > len(b) {
177 nb = len(b)
179 sa := bytestr(offset, a[0:na])
180 sb := bytestr(offset, b[0:nb])
181 if sa != sb {
182 s += fmt.Sprintf("-%v\n+%v\n", sa, sb)
184 a = a[na:]
185 b = b[nb:]
187 return s
190 func TestWriter(t *testing.T) {
191 testLoop:
192 for i, test := range writerTests {
193 expected, err := ioutil.ReadFile(test.file)
194 if err != nil {
195 t.Errorf("test %d: Unexpected error: %v", i, err)
196 continue
199 buf := new(bytes.Buffer)
200 tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
201 big := false
202 for j, entry := range test.entries {
203 big = big || entry.header.Size > 1<<10
204 if err := tw.WriteHeader(entry.header); err != nil {
205 t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
206 continue testLoop
208 if _, err := io.WriteString(tw, entry.contents); err != nil {
209 t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err)
210 continue testLoop
213 // Only interested in Close failures for the small tests.
214 if err := tw.Close(); err != nil && !big {
215 t.Errorf("test %d: Failed closing archive: %v", i, err)
216 continue testLoop
219 actual := buf.Bytes()
220 if !bytes.Equal(expected, actual) {
221 t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
222 i, bytediff(expected, actual))
224 if testing.Short() { // The second test is expensive.
225 break
230 func TestPax(t *testing.T) {
231 // Create an archive with a large name
232 fileinfo, err := os.Stat("testdata/small.txt")
233 if err != nil {
234 t.Fatal(err)
236 hdr, err := FileInfoHeader(fileinfo, "")
237 if err != nil {
238 t.Fatalf("os.Stat: %v", err)
240 // Force a PAX long name to be written
241 longName := strings.Repeat("ab", 100)
242 contents := strings.Repeat(" ", int(hdr.Size))
243 hdr.Name = longName
244 var buf bytes.Buffer
245 writer := NewWriter(&buf)
246 if err := writer.WriteHeader(hdr); err != nil {
247 t.Fatal(err)
249 if _, err = writer.Write([]byte(contents)); err != nil {
250 t.Fatal(err)
252 if err := writer.Close(); err != nil {
253 t.Fatal(err)
255 // Simple test to make sure PAX extensions are in effect
256 if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
257 t.Fatal("Expected at least one PAX header to be written.")
259 // Test that we can get a long name back out of the archive.
260 reader := NewReader(&buf)
261 hdr, err = reader.Next()
262 if err != nil {
263 t.Fatal(err)
265 if hdr.Name != longName {
266 t.Fatal("Couldn't recover long file name")
270 func TestPaxSymlink(t *testing.T) {
271 // Create an archive with a large linkname
272 fileinfo, err := os.Stat("testdata/small.txt")
273 if err != nil {
274 t.Fatal(err)
276 hdr, err := FileInfoHeader(fileinfo, "")
277 hdr.Typeflag = TypeSymlink
278 if err != nil {
279 t.Fatalf("os.Stat:1 %v", err)
281 // Force a PAX long linkname to be written
282 longLinkname := strings.Repeat("1234567890/1234567890", 10)
283 hdr.Linkname = longLinkname
285 hdr.Size = 0
286 var buf bytes.Buffer
287 writer := NewWriter(&buf)
288 if err := writer.WriteHeader(hdr); err != nil {
289 t.Fatal(err)
291 if err := writer.Close(); err != nil {
292 t.Fatal(err)
294 // Simple test to make sure PAX extensions are in effect
295 if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
296 t.Fatal("Expected at least one PAX header to be written.")
298 // Test that we can get a long name back out of the archive.
299 reader := NewReader(&buf)
300 hdr, err = reader.Next()
301 if err != nil {
302 t.Fatal(err)
304 if hdr.Linkname != longLinkname {
305 t.Fatal("Couldn't recover long link name")
309 func TestPaxNonAscii(t *testing.T) {
310 // Create an archive with non ascii. These should trigger a pax header
311 // because pax headers have a defined utf-8 encoding.
312 fileinfo, err := os.Stat("testdata/small.txt")
313 if err != nil {
314 t.Fatal(err)
317 hdr, err := FileInfoHeader(fileinfo, "")
318 if err != nil {
319 t.Fatalf("os.Stat:1 %v", err)
322 // some sample data
323 chineseFilename := "文件名"
324 chineseGroupname := "組"
325 chineseUsername := "用戶名"
327 hdr.Name = chineseFilename
328 hdr.Gname = chineseGroupname
329 hdr.Uname = chineseUsername
331 contents := strings.Repeat(" ", int(hdr.Size))
333 var buf bytes.Buffer
334 writer := NewWriter(&buf)
335 if err := writer.WriteHeader(hdr); err != nil {
336 t.Fatal(err)
338 if _, err = writer.Write([]byte(contents)); err != nil {
339 t.Fatal(err)
341 if err := writer.Close(); err != nil {
342 t.Fatal(err)
344 // Simple test to make sure PAX extensions are in effect
345 if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
346 t.Fatal("Expected at least one PAX header to be written.")
348 // Test that we can get a long name back out of the archive.
349 reader := NewReader(&buf)
350 hdr, err = reader.Next()
351 if err != nil {
352 t.Fatal(err)
354 if hdr.Name != chineseFilename {
355 t.Fatal("Couldn't recover unicode name")
357 if hdr.Gname != chineseGroupname {
358 t.Fatal("Couldn't recover unicode group")
360 if hdr.Uname != chineseUsername {
361 t.Fatal("Couldn't recover unicode user")
365 func TestPaxXattrs(t *testing.T) {
366 xattrs := map[string]string{
367 "user.key": "value",
370 // Create an archive with an xattr
371 fileinfo, err := os.Stat("testdata/small.txt")
372 if err != nil {
373 t.Fatal(err)
375 hdr, err := FileInfoHeader(fileinfo, "")
376 if err != nil {
377 t.Fatalf("os.Stat: %v", err)
379 contents := "Kilts"
380 hdr.Xattrs = xattrs
381 var buf bytes.Buffer
382 writer := NewWriter(&buf)
383 if err := writer.WriteHeader(hdr); err != nil {
384 t.Fatal(err)
386 if _, err = writer.Write([]byte(contents)); err != nil {
387 t.Fatal(err)
389 if err := writer.Close(); err != nil {
390 t.Fatal(err)
392 // Test that we can get the xattrs back out of the archive.
393 reader := NewReader(&buf)
394 hdr, err = reader.Next()
395 if err != nil {
396 t.Fatal(err)
398 if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
399 t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
400 hdr.Xattrs, xattrs)
404 func TestPAXHeader(t *testing.T) {
405 medName := strings.Repeat("CD", 50)
406 longName := strings.Repeat("AB", 100)
407 paxTests := [][2]string{
408 {paxPath + "=/etc/hosts", "19 path=/etc/hosts\n"},
409 {"a=b", "6 a=b\n"}, // Single digit length
410 {"a=names", "11 a=names\n"}, // Test case involving carries
411 {paxPath + "=" + longName, fmt.Sprintf("210 path=%s\n", longName)},
412 {paxPath + "=" + medName, fmt.Sprintf("110 path=%s\n", medName)}}
414 for _, test := range paxTests {
415 key, expected := test[0], test[1]
416 if result := paxHeader(key); result != expected {
417 t.Fatalf("paxHeader: got %s, expected %s", result, expected)
422 func TestUSTARLongName(t *testing.T) {
423 // Create an archive with a path that failed to split with USTAR extension in previous versions.
424 fileinfo, err := os.Stat("testdata/small.txt")
425 if err != nil {
426 t.Fatal(err)
428 hdr, err := FileInfoHeader(fileinfo, "")
429 hdr.Typeflag = TypeDir
430 if err != nil {
431 t.Fatalf("os.Stat:1 %v", err)
433 // Force a PAX long name to be written. The name was taken from a practical example
434 // that fails and replaced ever char through numbers to anonymize the sample.
435 longName := "/0000_0000000/00000-000000000/0000_0000000/00000-0000000000000/0000_0000000/00000-0000000-00000000/0000_0000000/00000000/0000_0000000/000/0000_0000000/00000000v00/0000_0000000/000000/0000_0000000/0000000/0000_0000000/00000y-00/0000/0000/00000000/0x000000/"
436 hdr.Name = longName
438 hdr.Size = 0
439 var buf bytes.Buffer
440 writer := NewWriter(&buf)
441 if err := writer.WriteHeader(hdr); err != nil {
442 t.Fatal(err)
444 if err := writer.Close(); err != nil {
445 t.Fatal(err)
447 // Test that we can get a long name back out of the archive.
448 reader := NewReader(&buf)
449 hdr, err = reader.Next()
450 if err != nil {
451 t.Fatal(err)
453 if hdr.Name != longName {
454 t.Fatal("Couldn't recover long name")