github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/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  	// FileInfoHeader should error when passing nil FileInfo
    40  	if _, err := FileInfoHeader(nil, ""); err == nil {
    41  		t.Fatalf("Expected error when passing nil to FileInfoHeader")
    42  	}
    43  }
    44  
    45  func TestFileInfoHeaderDir(t *testing.T) {
    46  	fi, err := os.Stat("testdata")
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	h, err := FileInfoHeader(fi, "")
    51  	if err != nil {
    52  		t.Fatalf("FileInfoHeader: %v", err)
    53  	}
    54  	if g, e := h.Name, "testdata/"; g != e {
    55  		t.Errorf("Name = %q; want %q", g, e)
    56  	}
    57  	// Ignoring c_ISGID for golang.org/issue/4867
    58  	if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e {
    59  		t.Errorf("Mode = %#o; want %#o", g, e)
    60  	}
    61  	if g, e := h.Size, int64(0); g != e {
    62  		t.Errorf("Size = %v; want %v", g, e)
    63  	}
    64  	if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
    65  		t.Errorf("ModTime = %v; want %v", g, e)
    66  	}
    67  }
    68  
    69  func TestFileInfoHeaderSymlink(t *testing.T) {
    70  	h, err := FileInfoHeader(symlink{}, "some-target")
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	if g, e := h.Name, "some-symlink"; g != e {
    75  		t.Errorf("Name = %q; want %q", g, e)
    76  	}
    77  	if g, e := h.Linkname, "some-target"; g != e {
    78  		t.Errorf("Linkname = %q; want %q", g, e)
    79  	}
    80  }
    81  
    82  type symlink struct{}
    83  
    84  func (symlink) Name() string       { return "some-symlink" }
    85  func (symlink) Size() int64        { return 0 }
    86  func (symlink) Mode() os.FileMode  { return os.ModeSymlink }
    87  func (symlink) ModTime() time.Time { return time.Time{} }
    88  func (symlink) IsDir() bool        { return false }
    89  func (symlink) Sys() interface{}   { return nil }
    90  
    91  func TestRoundTrip(t *testing.T) {
    92  	data := []byte("some file contents")
    93  
    94  	var b bytes.Buffer
    95  	tw := NewWriter(&b)
    96  	hdr := &Header{
    97  		Name: "file.txt",
    98  		Uid:  1 << 21, // too big for 8 octal digits
    99  		Size: int64(len(data)),
   100  		// AddDate to strip monotonic clock reading,
   101  		// and Round to discard sub-second precision,
   102  		// both of which are not included in the tar header
   103  		// and would otherwise break the round-trip check
   104  		// below.
   105  		ModTime: time.Now().AddDate(0, 0, 0).Round(1 * time.Second),
   106  	}
   107  	if err := tw.WriteHeader(hdr); err != nil {
   108  		t.Fatalf("tw.WriteHeader: %v", err)
   109  	}
   110  	if _, err := tw.Write(data); err != nil {
   111  		t.Fatalf("tw.Write: %v", err)
   112  	}
   113  	if err := tw.Close(); err != nil {
   114  		t.Fatalf("tw.Close: %v", err)
   115  	}
   116  
   117  	// Read it back.
   118  	tr := NewReader(&b)
   119  	rHdr, err := tr.Next()
   120  	if err != nil {
   121  		t.Fatalf("tr.Next: %v", err)
   122  	}
   123  	if !reflect.DeepEqual(rHdr, hdr) {
   124  		t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
   125  	}
   126  	rData, err := ioutil.ReadAll(tr)
   127  	if err != nil {
   128  		t.Fatalf("Read: %v", err)
   129  	}
   130  	if !bytes.Equal(rData, data) {
   131  		t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data)
   132  	}
   133  }
   134  
   135  type headerRoundTripTest struct {
   136  	h  *Header
   137  	fm os.FileMode
   138  }
   139  
   140  func TestHeaderRoundTrip(t *testing.T) {
   141  	vectors := []headerRoundTripTest{{
   142  		// regular file.
   143  		h: &Header{
   144  			Name:     "test.txt",
   145  			Mode:     0644 | c_ISREG,
   146  			Size:     12,
   147  			ModTime:  time.Unix(1360600916, 0),
   148  			Typeflag: TypeReg,
   149  		},
   150  		fm: 0644,
   151  	}, {
   152  		// symbolic link.
   153  		h: &Header{
   154  			Name:     "link.txt",
   155  			Mode:     0777 | c_ISLNK,
   156  			Size:     0,
   157  			ModTime:  time.Unix(1360600852, 0),
   158  			Typeflag: TypeSymlink,
   159  		},
   160  		fm: 0777 | os.ModeSymlink,
   161  	}, {
   162  		// character device node.
   163  		h: &Header{
   164  			Name:     "dev/null",
   165  			Mode:     0666 | c_ISCHR,
   166  			Size:     0,
   167  			ModTime:  time.Unix(1360578951, 0),
   168  			Typeflag: TypeChar,
   169  		},
   170  		fm: 0666 | os.ModeDevice | os.ModeCharDevice,
   171  	}, {
   172  		// block device node.
   173  		h: &Header{
   174  			Name:     "dev/sda",
   175  			Mode:     0660 | c_ISBLK,
   176  			Size:     0,
   177  			ModTime:  time.Unix(1360578954, 0),
   178  			Typeflag: TypeBlock,
   179  		},
   180  		fm: 0660 | os.ModeDevice,
   181  	}, {
   182  		// directory.
   183  		h: &Header{
   184  			Name:     "dir/",
   185  			Mode:     0755 | c_ISDIR,
   186  			Size:     0,
   187  			ModTime:  time.Unix(1360601116, 0),
   188  			Typeflag: TypeDir,
   189  		},
   190  		fm: 0755 | os.ModeDir,
   191  	}, {
   192  		// fifo node.
   193  		h: &Header{
   194  			Name:     "dev/initctl",
   195  			Mode:     0600 | c_ISFIFO,
   196  			Size:     0,
   197  			ModTime:  time.Unix(1360578949, 0),
   198  			Typeflag: TypeFifo,
   199  		},
   200  		fm: 0600 | os.ModeNamedPipe,
   201  	}, {
   202  		// setuid.
   203  		h: &Header{
   204  			Name:     "bin/su",
   205  			Mode:     0755 | c_ISREG | c_ISUID,
   206  			Size:     23232,
   207  			ModTime:  time.Unix(1355405093, 0),
   208  			Typeflag: TypeReg,
   209  		},
   210  		fm: 0755 | os.ModeSetuid,
   211  	}, {
   212  		// setguid.
   213  		h: &Header{
   214  			Name:     "group.txt",
   215  			Mode:     0750 | c_ISREG | c_ISGID,
   216  			Size:     0,
   217  			ModTime:  time.Unix(1360602346, 0),
   218  			Typeflag: TypeReg,
   219  		},
   220  		fm: 0750 | os.ModeSetgid,
   221  	}, {
   222  		// sticky.
   223  		h: &Header{
   224  			Name:     "sticky.txt",
   225  			Mode:     0600 | c_ISREG | c_ISVTX,
   226  			Size:     7,
   227  			ModTime:  time.Unix(1360602540, 0),
   228  			Typeflag: TypeReg,
   229  		},
   230  		fm: 0600 | os.ModeSticky,
   231  	}, {
   232  		// hard link.
   233  		h: &Header{
   234  			Name:     "hard.txt",
   235  			Mode:     0644 | c_ISREG,
   236  			Size:     0,
   237  			Linkname: "file.txt",
   238  			ModTime:  time.Unix(1360600916, 0),
   239  			Typeflag: TypeLink,
   240  		},
   241  		fm: 0644,
   242  	}, {
   243  		// More information.
   244  		h: &Header{
   245  			Name:     "info.txt",
   246  			Mode:     0600 | c_ISREG,
   247  			Size:     0,
   248  			Uid:      1000,
   249  			Gid:      1000,
   250  			ModTime:  time.Unix(1360602540, 0),
   251  			Uname:    "slartibartfast",
   252  			Gname:    "users",
   253  			Typeflag: TypeReg,
   254  		},
   255  		fm: 0600,
   256  	}}
   257  
   258  	for i, v := range vectors {
   259  		fi := v.h.FileInfo()
   260  		h2, err := FileInfoHeader(fi, "")
   261  		if err != nil {
   262  			t.Error(err)
   263  			continue
   264  		}
   265  		if strings.Contains(fi.Name(), "/") {
   266  			t.Errorf("FileInfo of %q contains slash: %q", v.h.Name, fi.Name())
   267  		}
   268  		name := path.Base(v.h.Name)
   269  		if fi.IsDir() {
   270  			name += "/"
   271  		}
   272  		if got, want := h2.Name, name; got != want {
   273  			t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
   274  		}
   275  		if got, want := h2.Size, v.h.Size; got != want {
   276  			t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
   277  		}
   278  		if got, want := h2.Uid, v.h.Uid; got != want {
   279  			t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
   280  		}
   281  		if got, want := h2.Gid, v.h.Gid; got != want {
   282  			t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
   283  		}
   284  		if got, want := h2.Uname, v.h.Uname; got != want {
   285  			t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
   286  		}
   287  		if got, want := h2.Gname, v.h.Gname; got != want {
   288  			t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
   289  		}
   290  		if got, want := h2.Linkname, v.h.Linkname; got != want {
   291  			t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
   292  		}
   293  		if got, want := h2.Typeflag, v.h.Typeflag; got != want {
   294  			t.Logf("%#v %#v", v.h, fi.Sys())
   295  			t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
   296  		}
   297  		if got, want := h2.Mode, v.h.Mode; got != want {
   298  			t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
   299  		}
   300  		if got, want := fi.Mode(), v.fm; got != want {
   301  			t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
   302  		}
   303  		if got, want := h2.AccessTime, v.h.AccessTime; got != want {
   304  			t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
   305  		}
   306  		if got, want := h2.ChangeTime, v.h.ChangeTime; got != want {
   307  			t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
   308  		}
   309  		if got, want := h2.ModTime, v.h.ModTime; got != want {
   310  			t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
   311  		}
   312  		if sysh, ok := fi.Sys().(*Header); !ok || sysh != v.h {
   313  			t.Errorf("i=%d: Sys didn't return original *Header", i)
   314  		}
   315  	}
   316  }