blob: ddd9ab7731c4c12daa110e97f2762b60df0acc94 [file] [log] [blame]
/*
* Copyright 2016 The Kythe Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package archive
import (
"archive/tar"
"archive/zip"
"bytes"
"compress/gzip"
"errors"
"io"
"io/ioutil"
"log"
"os"
"reflect"
"testing"
)
func newTar(files map[string]string) *bytes.Buffer {
buf := bytes.NewBuffer(nil)
w := tar.NewWriter(buf)
for name, data := range files {
if err := w.WriteHeader(&tar.Header{
Name: name,
Size: int64(len(data)),
}); err != nil {
log.Fatal("NewHeader: ", err)
}
if _, err := w.Write([]byte(data)); err != nil {
log.Fatal("Write: ", err)
}
}
if err := w.Close(); err != nil {
log.Fatal("Close: ", err)
}
return buf
}
func newZIP(files map[string]string) *bytes.Buffer {
buf := bytes.NewBuffer(nil)
w := zip.NewWriter(buf)
for name, data := range files {
f, err := w.Create(name)
if err != nil {
log.Fatal("Create: ", err)
} else if _, err := f.Write([]byte(data)); err != nil {
log.Fatal("Write: ", err)
}
}
if err := w.Close(); err != nil {
log.Fatal("Close: ", err)
}
return buf
}
func TestScanNothing(t *testing.T) {
var ignore *os.File
// These paths should not be recognized as archives.
for _, path := range []string{"foo", "foo/bar", "foo.gz", "foo.bz2", "a/b/foo.zippy"} {
err := Scan(ignore, path, func(name string, err error, rc io.Reader) error {
t.Errorf("ScanFunc was called with path=%q, err=%v, rc=%v", name, err, rc)
return nil
})
if err != ErrNotArchive {
t.Errorf("Scan(%q): got error %v, want %v", path, err, ErrNotArchive)
}
}
}
// byteFile implements the File interface around a *bytes.Reader. It adds a
// no-op Close method to complete the interface.
type byteFile struct{ *bytes.Reader }
func (b byteFile) Close() error { return nil }
func TestScanErrors(t *testing.T) {
file := byteFile{
Reader: bytes.NewReader(newZIP(map[string]string{
"this is not my hat": "♡",
}).Bytes()),
}
// Verify that an error returned by the callback is propagated.
want := errors.New("everything you know is wrong")
var got string
err := Scan(file, "fail.zip", func(name string, err error, r io.Reader) error {
got = name
return want
})
if err != want {
t.Errorf("Scan(fail.zip): got error %v, want %v", err, want)
}
if want := "this is not my hat"; got != want {
t.Errorf("Scan(fail.zip): got name %q, want %q", got, want)
}
}
func TestScanZIP(t *testing.T) {
files := map[string]string{
"devtools/grok/OWNERS": "stevey",
"file/base/file.h": "#include <stdio.h>",
"pyglib.app.py": "from __future__ import golang",
}
data := newZIP(files).Bytes()
// Each of these paths should be recognized as a ZIP file.
for _, path := range []string{"foo.zip", "bar.ZIP", "foo/bar.zip", "foo/bar/baz.plotz.zip", "ack/bar.jar"} {
file := byteFile{bytes.NewReader(data)}
got := make(map[string]string)
err := Scan(file, path, func(name string, err error, r io.Reader) error {
if err != nil {
return err
}
data, err := ioutil.ReadAll(r)
if err != nil {
return err
}
got[name] = string(data)
return nil
})
if err != nil {
t.Errorf("Scan(%q): unexpected error: %v", path, err)
}
if !reflect.DeepEqual(got, files) {
t.Errorf("Scan(%q):\n got %+v\nwant %+v", path, got, files)
}
}
}
func TestScanTar(t *testing.T) {
files := map[string]string{
"mapreduce/public/mapreduce.protodevel": `syntax = "proto3";`,
"file/base/BUILD": `cc_library(name = "recordio", ...)`,
"README.txt": "Lasciate ogni speranza, voi ch'entrate",
"third_party/README.md": `This directory is where your gross hacks go`,
}
data := newTar(files).Bytes()
gzdata := gzipData(data)
// Each of these paths should be recognized as a tar file.
tests := []struct {
path string
data []byte
}{
{"plain.tar", data},
{"foo/bar/plain.old.tar", data},
{"eat-a-tar.tar.gz", gzdata},
{"doom/and/chaos.tgz", gzdata},
}
for _, test := range tests {
file := byteFile{bytes.NewReader(test.data)}
got := make(map[string]string)
err := Scan(file, test.path, func(name string, err error, r io.Reader) error {
if err != nil {
return err
}
data, err := ioutil.ReadAll(r)
if err != nil {
return err
}
got[name] = string(data)
return nil
})
if err != nil {
t.Errorf("Scan(%q): unexpected error: %v", test.path, err)
}
if !reflect.DeepEqual(got, files) {
t.Errorf("Scan(%q):\n got %+v\nwant %+v", test.path, got, files)
}
}
}
func gzipData(data []byte) []byte {
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
if _, err := w.Write(data); err != nil {
log.Fatal("Write: ", err)
} else if err := w.Close(); err != nil {
log.Fatal("Close: ", err)
}
return buf.Bytes()
}