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