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 }