github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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  		ModTime: time.Now(),
   101  	}
   102  	// tar only supports second precision.
   103  	hdr.ModTime = hdr.ModTime.Add(-time.Duration(hdr.ModTime.Nanosecond()) * time.Nanosecond)
   104  	if err := tw.WriteHeader(hdr); err != nil {
   105  		t.Fatalf("tw.WriteHeader: %v", err)
   106  	}
   107  	if _, err := tw.Write(data); err != nil {
   108  		t.Fatalf("tw.Write: %v", err)
   109  	}
   110  	if err := tw.Close(); err != nil {
   111  		t.Fatalf("tw.Close: %v", err)
   112  	}
   113  
   114  	// Read it back.
   115  	tr := NewReader(&b)
   116  	rHdr, err := tr.Next()
   117  	if err != nil {
   118  		t.Fatalf("tr.Next: %v", err)
   119  	}
   120  	if !reflect.DeepEqual(rHdr, hdr) {
   121  		t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
   122  	}
   123  	rData, err := ioutil.ReadAll(tr)
   124  	if err != nil {
   125  		t.Fatalf("Read: %v", err)
   126  	}
   127  	if !bytes.Equal(rData, data) {
   128  		t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data)
   129  	}
   130  }
   131  
   132  type headerRoundTripTest struct {
   133  	h  *Header
   134  	fm os.FileMode
   135  }
   136  
   137  func TestHeaderRoundTrip(t *testing.T) {
   138  	golden := []headerRoundTripTest{
   139  		// regular file.
   140  		{
   141  			h: &Header{
   142  				Name:     "test.txt",
   143  				Mode:     0644 | c_ISREG,
   144  				Size:     12,
   145  				ModTime:  time.Unix(1360600916, 0),
   146  				Typeflag: TypeReg,
   147  			},
   148  			fm: 0644,
   149  		},
   150  		// symbolic link.
   151  		{
   152  			h: &Header{
   153  				Name:     "link.txt",
   154  				Mode:     0777 | c_ISLNK,
   155  				Size:     0,
   156  				ModTime:  time.Unix(1360600852, 0),
   157  				Typeflag: TypeSymlink,
   158  			},
   159  			fm: 0777 | os.ModeSymlink,
   160  		},
   161  		// character device node.
   162  		{
   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  		{
   174  			h: &Header{
   175  				Name:     "dev/sda",
   176  				Mode:     0660 | c_ISBLK,
   177  				Size:     0,
   178  				ModTime:  time.Unix(1360578954, 0),
   179  				Typeflag: TypeBlock,
   180  			},
   181  			fm: 0660 | os.ModeDevice,
   182  		},
   183  		// directory.
   184  		{
   185  			h: &Header{
   186  				Name:     "dir/",
   187  				Mode:     0755 | c_ISDIR,
   188  				Size:     0,
   189  				ModTime:  time.Unix(1360601116, 0),
   190  				Typeflag: TypeDir,
   191  			},
   192  			fm: 0755 | os.ModeDir,
   193  		},
   194  		// fifo node.
   195  		{
   196  			h: &Header{
   197  				Name:     "dev/initctl",
   198  				Mode:     0600 | c_ISFIFO,
   199  				Size:     0,
   200  				ModTime:  time.Unix(1360578949, 0),
   201  				Typeflag: TypeFifo,
   202  			},
   203  			fm: 0600 | os.ModeNamedPipe,
   204  		},
   205  		// setuid.
   206  		{
   207  			h: &Header{
   208  				Name:     "bin/su",
   209  				Mode:     0755 | c_ISREG | c_ISUID,
   210  				Size:     23232,
   211  				ModTime:  time.Unix(1355405093, 0),
   212  				Typeflag: TypeReg,
   213  			},
   214  			fm: 0755 | os.ModeSetuid,
   215  		},
   216  		// setguid.
   217  		{
   218  			h: &Header{
   219  				Name:     "group.txt",
   220  				Mode:     0750 | c_ISREG | c_ISGID,
   221  				Size:     0,
   222  				ModTime:  time.Unix(1360602346, 0),
   223  				Typeflag: TypeReg,
   224  			},
   225  			fm: 0750 | os.ModeSetgid,
   226  		},
   227  		// sticky.
   228  		{
   229  			h: &Header{
   230  				Name:     "sticky.txt",
   231  				Mode:     0600 | c_ISREG | c_ISVTX,
   232  				Size:     7,
   233  				ModTime:  time.Unix(1360602540, 0),
   234  				Typeflag: TypeReg,
   235  			},
   236  			fm: 0600 | os.ModeSticky,
   237  		},
   238  		// hard link.
   239  		{
   240  			h: &Header{
   241  				Name:     "hard.txt",
   242  				Mode:     0644 | c_ISREG,
   243  				Size:     0,
   244  				Linkname: "file.txt",
   245  				ModTime:  time.Unix(1360600916, 0),
   246  				Typeflag: TypeLink,
   247  			},
   248  			fm: 0644,
   249  		},
   250  		// More information.
   251  		{
   252  			h: &Header{
   253  				Name:     "info.txt",
   254  				Mode:     0600 | c_ISREG,
   255  				Size:     0,
   256  				Uid:      1000,
   257  				Gid:      1000,
   258  				ModTime:  time.Unix(1360602540, 0),
   259  				Uname:    "slartibartfast",
   260  				Gname:    "users",
   261  				Typeflag: TypeReg,
   262  			},
   263  			fm: 0600,
   264  		},
   265  	}
   266  
   267  	for i, g := range golden {
   268  		fi := g.h.FileInfo()
   269  		h2, err := FileInfoHeader(fi, "")
   270  		if err != nil {
   271  			t.Error(err)
   272  			continue
   273  		}
   274  		if strings.Contains(fi.Name(), "/") {
   275  			t.Errorf("FileInfo of %q contains slash: %q", g.h.Name, fi.Name())
   276  		}
   277  		name := path.Base(g.h.Name)
   278  		if fi.IsDir() {
   279  			name += "/"
   280  		}
   281  		if got, want := h2.Name, name; got != want {
   282  			t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
   283  		}
   284  		if got, want := h2.Size, g.h.Size; got != want {
   285  			t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
   286  		}
   287  		if got, want := h2.Uid, g.h.Uid; got != want {
   288  			t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
   289  		}
   290  		if got, want := h2.Gid, g.h.Gid; got != want {
   291  			t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
   292  		}
   293  		if got, want := h2.Uname, g.h.Uname; got != want {
   294  			t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
   295  		}
   296  		if got, want := h2.Gname, g.h.Gname; got != want {
   297  			t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
   298  		}
   299  		if got, want := h2.Linkname, g.h.Linkname; got != want {
   300  			t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
   301  		}
   302  		if got, want := h2.Typeflag, g.h.Typeflag; got != want {
   303  			t.Logf("%#v %#v", g.h, fi.Sys())
   304  			t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
   305  		}
   306  		if got, want := h2.Mode, g.h.Mode; got != want {
   307  			t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
   308  		}
   309  		if got, want := fi.Mode(), g.fm; got != want {
   310  			t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
   311  		}
   312  		if got, want := h2.AccessTime, g.h.AccessTime; got != want {
   313  			t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
   314  		}
   315  		if got, want := h2.ChangeTime, g.h.ChangeTime; got != want {
   316  			t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
   317  		}
   318  		if got, want := h2.ModTime, g.h.ModTime; got != want {
   319  			t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
   320  		}
   321  		if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
   322  			t.Errorf("i=%d: Sys didn't return original *Header", i)
   323  		}
   324  	}
   325  }