Source file src/compress/gzip/gzip_test.go

     1  // Copyright 2010 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 gzip
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"io"
    11  	"reflect"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  // TestEmpty tests that an empty payload still forms a valid GZIP stream.
    17  func TestEmpty(t *testing.T) {
    18  	buf := new(bytes.Buffer)
    19  
    20  	if err := NewWriter(buf).Close(); err != nil {
    21  		t.Fatalf("Writer.Close: %v", err)
    22  	}
    23  
    24  	r, err := NewReader(buf)
    25  	if err != nil {
    26  		t.Fatalf("NewReader: %v", err)
    27  	}
    28  	if want := (Header{OS: 255}); !reflect.DeepEqual(r.Header, want) {
    29  		t.Errorf("Header mismatch:\ngot  %#v\nwant %#v", r.Header, want)
    30  	}
    31  	b, err := io.ReadAll(r)
    32  	if err != nil {
    33  		t.Fatalf("ReadAll: %v", err)
    34  	}
    35  	if len(b) != 0 {
    36  		t.Fatalf("got %d bytes, want 0", len(b))
    37  	}
    38  	if err := r.Close(); err != nil {
    39  		t.Fatalf("Reader.Close: %v", err)
    40  	}
    41  }
    42  
    43  // TestRoundTrip tests that gzipping and then gunzipping is the identity
    44  // function.
    45  func TestRoundTrip(t *testing.T) {
    46  	buf := new(bytes.Buffer)
    47  
    48  	w := NewWriter(buf)
    49  	w.Comment = "comment"
    50  	w.Extra = []byte("extra")
    51  	w.ModTime = time.Unix(1e8, 0)
    52  	w.Name = "name"
    53  	if _, err := w.Write([]byte("payload")); err != nil {
    54  		t.Fatalf("Write: %v", err)
    55  	}
    56  	if err := w.Close(); err != nil {
    57  		t.Fatalf("Writer.Close: %v", err)
    58  	}
    59  
    60  	r, err := NewReader(buf)
    61  	if err != nil {
    62  		t.Fatalf("NewReader: %v", err)
    63  	}
    64  	b, err := io.ReadAll(r)
    65  	if err != nil {
    66  		t.Fatalf("ReadAll: %v", err)
    67  	}
    68  	if string(b) != "payload" {
    69  		t.Fatalf("payload is %q, want %q", string(b), "payload")
    70  	}
    71  	if r.Comment != "comment" {
    72  		t.Fatalf("comment is %q, want %q", r.Comment, "comment")
    73  	}
    74  	if string(r.Extra) != "extra" {
    75  		t.Fatalf("extra is %q, want %q", r.Extra, "extra")
    76  	}
    77  	if r.ModTime.Unix() != 1e8 {
    78  		t.Fatalf("mtime is %d, want %d", r.ModTime.Unix(), uint32(1e8))
    79  	}
    80  	if r.Name != "name" {
    81  		t.Fatalf("name is %q, want %q", r.Name, "name")
    82  	}
    83  	if err := r.Close(); err != nil {
    84  		t.Fatalf("Reader.Close: %v", err)
    85  	}
    86  }
    87  
    88  // TestLatin1 tests the internal functions for converting to and from Latin-1.
    89  func TestLatin1(t *testing.T) {
    90  	latin1 := []byte{0xc4, 'u', 0xdf, 'e', 'r', 'u', 'n', 'g', 0}
    91  	utf8 := "Äußerung"
    92  	z := Reader{r: bufio.NewReader(bytes.NewReader(latin1))}
    93  	s, err := z.readString()
    94  	if err != nil {
    95  		t.Fatalf("readString: %v", err)
    96  	}
    97  	if s != utf8 {
    98  		t.Fatalf("read latin-1: got %q, want %q", s, utf8)
    99  	}
   100  
   101  	buf := bytes.NewBuffer(make([]byte, 0, len(latin1)))
   102  	c := Writer{w: buf}
   103  	if err = c.writeString(utf8); err != nil {
   104  		t.Fatalf("writeString: %v", err)
   105  	}
   106  	s = buf.String()
   107  	if s != string(latin1) {
   108  		t.Fatalf("write utf-8: got %q, want %q", s, string(latin1))
   109  	}
   110  }
   111  
   112  // TestLatin1RoundTrip tests that metadata that is representable in Latin-1
   113  // survives a round trip.
   114  func TestLatin1RoundTrip(t *testing.T) {
   115  	testCases := []struct {
   116  		name string
   117  		ok   bool
   118  	}{
   119  		{"", true},
   120  		{"ASCII is OK", true},
   121  		{"unless it contains a NUL\x00", false},
   122  		{"no matter where \x00 occurs", false},
   123  		{"\x00\x00\x00", false},
   124  		{"Látin-1 also passes (U+00E1)", true},
   125  		{"but LĀtin Extended-A (U+0100) does not", false},
   126  		{"neither does 日本語", false},
   127  		{"invalid UTF-8 also \xffails", false},
   128  		{"\x00 as does Látin-1 with NUL", false},
   129  	}
   130  	for _, tc := range testCases {
   131  		buf := new(bytes.Buffer)
   132  
   133  		w := NewWriter(buf)
   134  		w.Name = tc.name
   135  		err := w.Close()
   136  		if (err == nil) != tc.ok {
   137  			t.Errorf("Writer.Close: name = %q, err = %v", tc.name, err)
   138  			continue
   139  		}
   140  		if !tc.ok {
   141  			continue
   142  		}
   143  
   144  		r, err := NewReader(buf)
   145  		if err != nil {
   146  			t.Errorf("NewReader: %v", err)
   147  			continue
   148  		}
   149  		_, err = io.ReadAll(r)
   150  		if err != nil {
   151  			t.Errorf("ReadAll: %v", err)
   152  			continue
   153  		}
   154  		if r.Name != tc.name {
   155  			t.Errorf("name is %q, want %q", r.Name, tc.name)
   156  			continue
   157  		}
   158  		if err := r.Close(); err != nil {
   159  			t.Errorf("Reader.Close: %v", err)
   160  			continue
   161  		}
   162  	}
   163  }
   164  
   165  func TestWriterFlush(t *testing.T) {
   166  	buf := new(bytes.Buffer)
   167  
   168  	w := NewWriter(buf)
   169  	w.Comment = "comment"
   170  	w.Extra = []byte("extra")
   171  	w.ModTime = time.Unix(1e8, 0)
   172  	w.Name = "name"
   173  
   174  	n0 := buf.Len()
   175  	if n0 != 0 {
   176  		t.Fatalf("buffer size = %d before writes; want 0", n0)
   177  	}
   178  
   179  	if err := w.Flush(); err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	n1 := buf.Len()
   184  	if n1 == 0 {
   185  		t.Fatal("no data after first flush")
   186  	}
   187  
   188  	w.Write([]byte("x"))
   189  
   190  	n2 := buf.Len()
   191  	if n1 != n2 {
   192  		t.Fatalf("after writing a single byte, size changed from %d to %d; want no change", n1, n2)
   193  	}
   194  
   195  	if err := w.Flush(); err != nil {
   196  		t.Fatal(err)
   197  	}
   198  
   199  	n3 := buf.Len()
   200  	if n2 == n3 {
   201  		t.Fatal("Flush didn't flush any data")
   202  	}
   203  
   204  	if err := w.Close(); err != nil {
   205  		t.Fatal(err)
   206  	}
   207  
   208  }
   209  
   210  // Multiple gzip files concatenated form a valid gzip file.
   211  func TestConcat(t *testing.T) {
   212  	var buf bytes.Buffer
   213  	w := NewWriter(&buf)
   214  	w.Write([]byte("hello "))
   215  	w.Close()
   216  	w = NewWriter(&buf)
   217  	w.Write([]byte("world\n"))
   218  	w.Close()
   219  
   220  	r, err := NewReader(&buf)
   221  	if err != nil {
   222  		t.Fatal(err)
   223  	}
   224  	data, err := io.ReadAll(r)
   225  	if string(data) != "hello world\n" || err != nil {
   226  		t.Fatalf("ReadAll = %q, %v, want %q, nil", data, err, "hello world")
   227  	}
   228  }
   229  
   230  func TestWriterReset(t *testing.T) {
   231  	buf := new(bytes.Buffer)
   232  	buf2 := new(bytes.Buffer)
   233  	z := NewWriter(buf)
   234  	msg := []byte("hello world")
   235  	z.Write(msg)
   236  	z.Close()
   237  	z.Reset(buf2)
   238  	z.Write(msg)
   239  	z.Close()
   240  	if buf.String() != buf2.String() {
   241  		t.Errorf("buf2 %q != original buf of %q", buf2.String(), buf.String())
   242  	}
   243  }
   244  
   245  type limitedWriter struct {
   246  	N int
   247  }
   248  
   249  func (l *limitedWriter) Write(p []byte) (n int, err error) {
   250  	if n := l.N; n < len(p) {
   251  		l.N = 0
   252  		return n, io.ErrShortWrite
   253  	}
   254  	l.N -= len(p)
   255  	return len(p), nil
   256  }
   257  
   258  // Write should never return more bytes than the input slice.
   259  func TestLimitedWrite(t *testing.T) {
   260  	msg := []byte("a")
   261  
   262  	for lim := 2; lim < 20; lim++ {
   263  		z := NewWriter(&limitedWriter{lim})
   264  		if n, _ := z.Write(msg); n > len(msg) {
   265  			t.Errorf("Write() = %d, want %d or less", n, len(msg))
   266  		}
   267  
   268  		z.Reset(&limitedWriter{lim})
   269  		z.Header = Header{
   270  			Comment: "comment",
   271  			Extra:   []byte("extra"),
   272  			ModTime: time.Now(),
   273  			Name:    "name",
   274  			OS:      1,
   275  		}
   276  		if n, _ := z.Write(msg); n > len(msg) {
   277  			t.Errorf("Write() = %d, want %d or less", n, len(msg))
   278  		}
   279  	}
   280  }
   281  

View as plain text