github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/archive/tar/tar_test.go (about) 1 // Copyright 2012 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. 4 5 package tar 6 7 import ( 8 "bytes" 9 "io/ioutil" 10 "os" 11 "path" 12 "reflect" 13 "strings" 14 "testing" 15 "time" 16 ) 17 18 func TestFileInfoHeader(t *testing.T) { 19 fi, err := os.Stat("testdata/small.txt") 20 if err != nil { 21 t.Fatal(err) 22 } 23 h, err := FileInfoHeader(fi, "") 24 if err != nil { 25 t.Fatalf("FileInfoHeader: %v", err) 26 } 27 if g, e := h.Name, "small.txt"; g != e { 28 t.Errorf("Name = %q; want %q", g, e) 29 } 30 if g, e := h.Mode, int64(fi.Mode().Perm())|c_ISREG; g != e { 31 t.Errorf("Mode = %#o; want %#o", g, e) 32 } 33 if g, e := h.Size, int64(5); g != e { 34 t.Errorf("Size = %v; want %v", g, e) 35 } 36 if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) { 37 t.Errorf("ModTime = %v; want %v", g, e) 38 } 39 } 40 41 func TestFileInfoHeaderDir(t *testing.T) { 42 fi, err := os.Stat("testdata") 43 if err != nil { 44 t.Fatal(err) 45 } 46 h, err := FileInfoHeader(fi, "") 47 if err != nil { 48 t.Fatalf("FileInfoHeader: %v", err) 49 } 50 if g, e := h.Name, "testdata/"; g != e { 51 t.Errorf("Name = %q; want %q", g, e) 52 } 53 // Ignoring c_ISGID for golang.org/issue/4867 54 if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e { 55 t.Errorf("Mode = %#o; want %#o", g, e) 56 } 57 if g, e := h.Size, int64(0); g != e { 58 t.Errorf("Size = %v; want %v", g, e) 59 } 60 if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) { 61 t.Errorf("ModTime = %v; want %v", g, e) 62 } 63 } 64 65 func TestFileInfoHeaderSymlink(t *testing.T) { 66 h, err := FileInfoHeader(symlink{}, "some-target") 67 if err != nil { 68 t.Fatal(err) 69 } 70 if g, e := h.Name, "some-symlink"; g != e { 71 t.Errorf("Name = %q; want %q", g, e) 72 } 73 if g, e := h.Linkname, "some-target"; g != e { 74 t.Errorf("Linkname = %q; want %q", g, e) 75 } 76 } 77 78 type symlink struct{} 79 80 func (symlink) Name() string { return "some-symlink" } 81 func (symlink) Size() int64 { return 0 } 82 func (symlink) Mode() os.FileMode { return os.ModeSymlink } 83 func (symlink) ModTime() time.Time { return time.Time{} } 84 func (symlink) IsDir() bool { return false } 85 func (symlink) Sys() interface{} { return nil } 86 87 func TestRoundTrip(t *testing.T) { 88 data := []byte("some file contents") 89 90 var b bytes.Buffer 91 tw := NewWriter(&b) 92 hdr := &Header{ 93 Name: "file.txt", 94 Uid: 1 << 21, // too big for 8 octal digits 95 Size: int64(len(data)), 96 ModTime: time.Now(), 97 } 98 // tar only supports second precision. 99 hdr.ModTime = hdr.ModTime.Add(-time.Duration(hdr.ModTime.Nanosecond()) * time.Nanosecond) 100 if err := tw.WriteHeader(hdr); err != nil { 101 t.Fatalf("tw.WriteHeader: %v", err) 102 } 103 if _, err := tw.Write(data); err != nil { 104 t.Fatalf("tw.Write: %v", err) 105 } 106 if err := tw.Close(); err != nil { 107 t.Fatalf("tw.Close: %v", err) 108 } 109 110 // Read it back. 111 tr := NewReader(&b) 112 rHdr, err := tr.Next() 113 if err != nil { 114 t.Fatalf("tr.Next: %v", err) 115 } 116 if !reflect.DeepEqual(rHdr, hdr) { 117 t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr) 118 } 119 rData, err := ioutil.ReadAll(tr) 120 if err != nil { 121 t.Fatalf("Read: %v", err) 122 } 123 if !bytes.Equal(rData, data) { 124 t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data) 125 } 126 } 127 128 type headerRoundTripTest struct { 129 h *Header 130 fm os.FileMode 131 } 132 133 func TestHeaderRoundTrip(t *testing.T) { 134 golden := []headerRoundTripTest{ 135 // regular file. 136 { 137 h: &Header{ 138 Name: "test.txt", 139 Mode: 0644 | c_ISREG, 140 Size: 12, 141 ModTime: time.Unix(1360600916, 0), 142 Typeflag: TypeReg, 143 }, 144 fm: 0644, 145 }, 146 // hard link. 147 { 148 h: &Header{ 149 Name: "hard.txt", 150 Mode: 0644 | c_ISLNK, 151 Size: 0, 152 ModTime: time.Unix(1360600916, 0), 153 Typeflag: TypeLink, 154 }, 155 fm: 0644 | os.ModeSymlink, 156 }, 157 // symbolic link. 158 { 159 h: &Header{ 160 Name: "link.txt", 161 Mode: 0777 | c_ISLNK, 162 Size: 0, 163 ModTime: time.Unix(1360600852, 0), 164 Typeflag: TypeSymlink, 165 }, 166 fm: 0777 | os.ModeSymlink, 167 }, 168 // character device node. 169 { 170 h: &Header{ 171 Name: "dev/null", 172 Mode: 0666 | c_ISCHR, 173 Size: 0, 174 ModTime: time.Unix(1360578951, 0), 175 Typeflag: TypeChar, 176 }, 177 fm: 0666 | os.ModeDevice | os.ModeCharDevice, 178 }, 179 // block device node. 180 { 181 h: &Header{ 182 Name: "dev/sda", 183 Mode: 0660 | c_ISBLK, 184 Size: 0, 185 ModTime: time.Unix(1360578954, 0), 186 Typeflag: TypeBlock, 187 }, 188 fm: 0660 | os.ModeDevice, 189 }, 190 // directory. 191 { 192 h: &Header{ 193 Name: "dir/", 194 Mode: 0755 | c_ISDIR, 195 Size: 0, 196 ModTime: time.Unix(1360601116, 0), 197 Typeflag: TypeDir, 198 }, 199 fm: 0755 | os.ModeDir, 200 }, 201 // fifo node. 202 { 203 h: &Header{ 204 Name: "dev/initctl", 205 Mode: 0600 | c_ISFIFO, 206 Size: 0, 207 ModTime: time.Unix(1360578949, 0), 208 Typeflag: TypeFifo, 209 }, 210 fm: 0600 | os.ModeNamedPipe, 211 }, 212 // setuid. 213 { 214 h: &Header{ 215 Name: "bin/su", 216 Mode: 0755 | c_ISREG | c_ISUID, 217 Size: 23232, 218 ModTime: time.Unix(1355405093, 0), 219 Typeflag: TypeReg, 220 }, 221 fm: 0755 | os.ModeSetuid, 222 }, 223 // setguid. 224 { 225 h: &Header{ 226 Name: "group.txt", 227 Mode: 0750 | c_ISREG | c_ISGID, 228 Size: 0, 229 ModTime: time.Unix(1360602346, 0), 230 Typeflag: TypeReg, 231 }, 232 fm: 0750 | os.ModeSetgid, 233 }, 234 // sticky. 235 { 236 h: &Header{ 237 Name: "sticky.txt", 238 Mode: 0600 | c_ISREG | c_ISVTX, 239 Size: 7, 240 ModTime: time.Unix(1360602540, 0), 241 Typeflag: TypeReg, 242 }, 243 fm: 0600 | os.ModeSticky, 244 }, 245 } 246 247 for i, g := range golden { 248 fi := g.h.FileInfo() 249 h2, err := FileInfoHeader(fi, "") 250 if err != nil { 251 t.Error(err) 252 continue 253 } 254 if strings.Contains(fi.Name(), "/") { 255 t.Errorf("FileInfo of %q contains slash: %q", g.h.Name, fi.Name()) 256 } 257 name := path.Base(g.h.Name) 258 if fi.IsDir() { 259 name += "/" 260 } 261 if got, want := h2.Name, name; got != want { 262 t.Errorf("i=%d: Name: got %v, want %v", i, got, want) 263 } 264 if got, want := h2.Size, g.h.Size; got != want { 265 t.Errorf("i=%d: Size: got %v, want %v", i, got, want) 266 } 267 if got, want := h2.Mode, g.h.Mode; got != want { 268 t.Errorf("i=%d: Mode: got %o, want %o", i, got, want) 269 } 270 if got, want := fi.Mode(), g.fm; got != want { 271 t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want) 272 } 273 if got, want := h2.ModTime, g.h.ModTime; got != want { 274 t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want) 275 } 276 if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h { 277 t.Errorf("i=%d: Sys didn't return original *Header", i) 278 } 279 } 280 }