kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/util/archive/reader_test.go (about)

     1  /*
     2   * Copyright 2016 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package archive
    18  
    19  import (
    20  	"archive/tar"
    21  	"archive/zip"
    22  	"bytes"
    23  	"compress/gzip"
    24  	"errors"
    25  	"io"
    26  	"io/ioutil"
    27  	"os"
    28  	"reflect"
    29  	"testing"
    30  
    31  	"kythe.io/kythe/go/util/log"
    32  )
    33  
    34  func newTar(files map[string]string) *bytes.Buffer {
    35  	buf := bytes.NewBuffer(nil)
    36  	w := tar.NewWriter(buf)
    37  	for name, data := range files {
    38  		if err := w.WriteHeader(&tar.Header{
    39  			Name: name,
    40  			Size: int64(len(data)),
    41  		}); err != nil {
    42  			log.Fatal("NewHeader: ", err)
    43  		}
    44  		if _, err := w.Write([]byte(data)); err != nil {
    45  			log.Fatal("Write: ", err)
    46  		}
    47  	}
    48  	if err := w.Close(); err != nil {
    49  		log.Fatal("Close: ", err)
    50  	}
    51  	return buf
    52  }
    53  
    54  func newZIP(files map[string]string) *bytes.Buffer {
    55  	buf := bytes.NewBuffer(nil)
    56  	w := zip.NewWriter(buf)
    57  	for name, data := range files {
    58  		f, err := w.Create(name)
    59  		if err != nil {
    60  			log.Fatal("Create: ", err)
    61  		} else if _, err := f.Write([]byte(data)); err != nil {
    62  			log.Fatal("Write: ", err)
    63  		}
    64  	}
    65  	if err := w.Close(); err != nil {
    66  		log.Fatal("Close: ", err)
    67  	}
    68  	return buf
    69  }
    70  
    71  func TestScanNothing(t *testing.T) {
    72  	var ignore *os.File
    73  
    74  	// These paths should not be recognized as archives.
    75  	for _, path := range []string{"foo", "foo/bar", "foo.gz", "foo.bz2", "a/b/foo.zippy"} {
    76  		err := Scan(ignore, path, func(name string, err error, rc io.Reader) error {
    77  			t.Errorf("ScanFunc was called with path=%q, err=%v, rc=%v", name, err, rc)
    78  			return nil
    79  		})
    80  		if err != ErrNotArchive {
    81  			t.Errorf("Scan(%q): got error %v, want %v", path, err, ErrNotArchive)
    82  		}
    83  	}
    84  }
    85  
    86  // byteFile implements the File interface around a *bytes.Reader.  It adds a
    87  // no-op Close method to complete the interface.
    88  type byteFile struct{ *bytes.Reader }
    89  
    90  func (b byteFile) Close() error { return nil }
    91  
    92  func TestScanErrors(t *testing.T) {
    93  	file := byteFile{
    94  		Reader: bytes.NewReader(newZIP(map[string]string{
    95  			"this is not my hat": "♡",
    96  		}).Bytes()),
    97  	}
    98  
    99  	// Verify that an error returned by the callback is propagated.
   100  	want := errors.New("everything you know is wrong")
   101  	var got string
   102  	err := Scan(file, "fail.zip", func(name string, err error, r io.Reader) error {
   103  		got = name
   104  		return want
   105  	})
   106  	if err != want {
   107  		t.Errorf("Scan(fail.zip): got error %v, want %v", err, want)
   108  	}
   109  	if want := "this is not my hat"; got != want {
   110  		t.Errorf("Scan(fail.zip): got name %q, want %q", got, want)
   111  	}
   112  }
   113  
   114  func TestScanZIP(t *testing.T) {
   115  	files := map[string]string{
   116  		"devtools/grok/OWNERS": "stevey",
   117  		"file/base/file.h":     "#include <stdio.h>",
   118  		"pyglib.app.py":        "from __future__ import golang",
   119  	}
   120  	data := newZIP(files).Bytes()
   121  
   122  	// Each of these paths should be recognized as a ZIP file.
   123  	for _, path := range []string{"foo.zip", "bar.ZIP", "foo/bar.zip", "foo/bar/baz.plotz.zip", "ack/bar.jar"} {
   124  		file := byteFile{bytes.NewReader(data)}
   125  		got := make(map[string]string)
   126  
   127  		err := Scan(file, path, func(name string, err error, r io.Reader) error {
   128  			if err != nil {
   129  				return err
   130  			}
   131  			data, err := ioutil.ReadAll(r)
   132  			if err != nil {
   133  				return err
   134  			}
   135  			got[name] = string(data)
   136  			return nil
   137  		})
   138  		if err != nil {
   139  			t.Errorf("Scan(%q): unexpected error: %v", path, err)
   140  		}
   141  
   142  		if !reflect.DeepEqual(got, files) {
   143  			t.Errorf("Scan(%q):\n got %+v\nwant %+v", path, got, files)
   144  		}
   145  	}
   146  }
   147  
   148  func TestScanTar(t *testing.T) {
   149  	files := map[string]string{
   150  		"mapreduce/public/mapreduce.protodevel": `syntax = "proto3";`,
   151  		"file/base/BUILD":                       `cc_library(name = "recordio", ...)`,
   152  		"README.txt":                            "Lasciate ogni speranza, voi ch'entrate",
   153  		"third_party/README.md":                 `This directory is where your gross hacks go`,
   154  	}
   155  	data := newTar(files).Bytes()
   156  	gzdata := gzipData(data)
   157  
   158  	// Each of these paths should be recognized as a tar file.
   159  	tests := []struct {
   160  		path string
   161  		data []byte
   162  	}{
   163  		{"plain.tar", data},
   164  		{"foo/bar/plain.old.tar", data},
   165  		{"eat-a-tar.tar.gz", gzdata},
   166  		{"doom/and/chaos.tgz", gzdata},
   167  	}
   168  	for _, test := range tests {
   169  		file := byteFile{bytes.NewReader(test.data)}
   170  		got := make(map[string]string)
   171  
   172  		err := Scan(file, test.path, func(name string, err error, r io.Reader) error {
   173  			if err != nil {
   174  				return err
   175  			}
   176  			data, err := ioutil.ReadAll(r)
   177  			if err != nil {
   178  				return err
   179  			}
   180  			got[name] = string(data)
   181  			return nil
   182  		})
   183  		if err != nil {
   184  			t.Errorf("Scan(%q): unexpected error: %v", test.path, err)
   185  		}
   186  
   187  		if !reflect.DeepEqual(got, files) {
   188  			t.Errorf("Scan(%q):\n got %+v\nwant %+v", test.path, got, files)
   189  		}
   190  	}
   191  }
   192  
   193  func gzipData(data []byte) []byte {
   194  	var buf bytes.Buffer
   195  	w := gzip.NewWriter(&buf)
   196  	if _, err := w.Write(data); err != nil {
   197  		log.Fatal("Write: ", err)
   198  	} else if err := w.Close(); err != nil {
   199  		log.Fatal("Close: ", err)
   200  	}
   201  	return buf.Bytes()
   202  }